Preencher o aCols de uma tela padrão | Ti Responde 048

No vídeo de hoje, vamos demonstrar em como replicar informações em várias linhas de uma tela que utiliza aCols.

A dúvida de hoje foi do grande Gilberto, onde ele perguntou como poderia fazer um recurso onde replicasse uma informação em todas as linhas de uma tela que usa aCols.

Pensando nisso montamos um exemplo onde ao clicar em Outras Ações, existe uma opção para replicar a informação em todas as linhas (foi usado como exemplo a tela de Documento de Entrada – MATA103).

E abaixo o código fonte desenvolvido para exemplificar:

 

//Bibliotecas
#Include "TOTVS.ch"

/*/{Protheus.doc} User Function MA103BUT
Ponto de Entrada para adicionar uma opção dentro do outras ações do Documento de Entrada
@type  Function
@author Atilio
@since 26/07/2021
@see https://tdn.totvs.com/pages/releaseview.action?pageId=102269141
/*/

User Function MA103BUT()
	Local aArea   := FWGetArea()
	Local aAreaF1 := SF1->(FWGetArea())
	Local aAreaD1 := SD1->(FWGetArea())
	Local aBotao  := {}
	
	aAdd( aBotao, { "BUDGETY"  , { || u_zVid0048()  } , "* Alt. Alíquota IPI" } )

	FWRestArea(aAreaD1)
	FWRestArea(aAreaF1)
	FWRestArea(aArea)
Return aBotao

/*/{Protheus.doc} User Function zVid0048
Função que altera a alíquota do IPI de todas as linhas, conforme digitado numa tela de parâmetro
@type  Function
@author Atilio
@since 26/07/2021
@version version
/*/

User Function zVid0048()
	Local aArea    := GetArea()
	Local nBkp     := n
    Local cCampo   := "D1_IPI"
	Local nPosAliq := GDFieldPos(cCampo)
	Local nAliqNov := 0
	Local cVldSis  := GetSX3Cache(cCampo, "X3_VALID")
	Local cVldUsr  := GetSX3Cache(cCampo, "X3_VLDUSER")
	Local aPergs   := {}
	Local nAtual   := 0
	Local lValidou := .T.
	
	//Adiciona os parâmetros que serão exibidos
	aAdd(aPergs, {1, "Aliq. ICMS",  nAliqNov,  PesqPict("SD1", cCampo), "Positivo()", "", ".T.", 80,  .T.})
	
	//Se a pergunta for confirmada
	If ParamBox(aPergs, "Informe os parâmetros", , , , , , , , , .F., .F.)
		nAliqNov := MV_PAR01
	
		//Percorre todas as linhas da grid
		For nAtual := 1 To Len(aCols)
			lValidou := .T.

			//Altera a linha posicionada na memória
			n := nAtual

			//Altera o ReadVar da Memória
			__ReadVar  := "M->" + cCampo
			M->D1_IPI := nAliqNov

			//Chama a validação do sistema
			If ! Empty(cVldSis)
				lValidou := &(cVldSis)
			EndIf

			//Chama a validação de usuário
			If ! Empty(cVldUsr) .And. lValidou
				lValidou := &(cVldUsr)
			EndIf

			//Se deu certo as validações
			If lValidou
				//Altera a informação de alíquota direto no aCols
				aCols[n][nPosAliq] := nAliqNov

				//Chama gatilho caso exista
				If ExistTrigger(cCampo)
					RunTrigger( ;
						2,;           //nTipo (1=Enchoice; 2=GetDados; 3=F3)
						n,;           //Linha atual da Grid quando for tipo 2
						Nil,;         //Não utilizado
						,;            //Objeto quando for tipo 1
						cCampo;       //Campo que dispara o gatilho
					)
				EndIf
			EndIf
		Next
	EndIf

	n := nBkp
	GetDRefresh()
	RestArea(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.

19 Responses

  1. JOSE EULALIO SOARES DOS SANTOS disse:

    Muito bom o artigo, parabéns! Seria legal fazer um sobre simular manter o aCols preenchido em rotinas em MVC. Existem muitos lugares que tem dificuldade em atualizar suas rotinas pq boa parte do dicionário e rotinas auxiliares estão usando aHeader e aCols e não atualizam para MVC, pois teriam que atualizar o dicionário e todas essas rotinas de uma vez só para dar certo.

  2. Alexandre Behling disse:

    Uma dica, como não muda o campo dentro do laço pode checar se tem gatilho apenas uma vez fora do laço e gravar numa variável lógica, então caso seja True é só executar o o gatilho sem precisar toda vez verificar no dicionário se tem o gatilho.

  3. Jose Cristiano disse:

    Ola boa noite tudo bem?
    Primeiramente otimo artigo muita qualidade e clareza..
    Uma duvida que percebi quando pego algum campo como D1_tes ou d1_CF que sao campos que tem pesquisa ele nao aparece para editar exemplo TES ele so aparece para digitar um caracter sendo que ele precisa ter 3 ,para esses casos tem alguma trativa ou dica de como pode tratar essa situacao?

    • Bom dia José, tudo joia graças a Deus e você?

      Opa, obrigado pelo feedback.

      Então, você diz na tela de parâmetros? Se sim, para o tipo caractere, você precisa inicializar a variável já com os espaços disponíveis para a digitação. Por exemplo, supondo que você queira 3 caracteres:

      cSuaVar := Space(3)
      

      Ou você pode simplesmente pegar o tamanho do campo no banco, exemplo:

      cSuaVar := Space(TamSX3('D1_TES')[1])
      

      E ai por fim, você coloca no seu ParamBox:

      aAdd(aPergs, {1, "TES",  cSuaVar,  "", ".T.", "SF4", ".T.", 60,  .T.})
      

      Abraços.

  4. Jose Grigorini disse:

    Ola boa noite Tudo bem?
    Primeiramente obrigado por compartilhar conhecimento .
    Dentro desse exemplo seria possível eu considerar a alíquota da linha anterior e replicar para as demais em vez de usar a que foi digitado no pergunte?

    • Bom dia José, tudo joia graças a Deus e você?

      Acha, nós que agradecemos pelo comentário.

      Então, supondo que você quer replicar as informações da alíquota da linha de número 1, o que será necessário será o seguinte:

      1. Comentar o trecho que tem do ParamBox (linhas 46 e 49 do exemplo)
      2. Antes do For, a variável nAliqNov, você atribui nela, o valor da primeira linha, algo +- assim: nAliqNov := aCols[1][nPosAliq]

      Forte abraço.

  5. CLEBERSON DA SILVA disse:

    Daniel Atilio parabén pelo conteudo,

    No meu caso preciso replicar o campo C6_NUMPCOM porem ao aplicar a sugestão que deu não valida!

    Local aArea := GetArea()
    Local nBkp := n
    Local cCampo := “C6_NUMPCOM”
    Local nPosPedCom := GDFieldPos(cCampo)
    Local nAliqNov := Space(TamSX3(‘C6_NUMPCOM’)[1])
    Local cVldSis := GetSX3Cache(cCampo, “X3_VALID”)
    Local cVldUsr := GetSX3Cache(cCampo, “X3_VLDUSER”)
    Local aPergs := {}
    Local nAtual := 0
    Local lValidou := .T.

    //Adiciona os parâmetros que serão exibidos

    aAdd(aPergs, {1, “nPedido”, nAliqNov, “”, “.T.”, “SC6”, “.T.”, 60, .T.})
    //aAdd(aPergs, {1, “Num Pedido”, nAliqNov, PesqPict(“SC6”, cCampo), “Positivo()”, “”, “.T.”, 80, .T.})

    • Bom dia Cleberson, tudo joia?

      Opa, primeiramente, obrigado pelo comentário e feedback, é muita bondade sua.

      Consultei aqui, e o campo “C6_NUMPCOM” não tem validações de campo (X3_VALID e X3_VLDUSER) e também não tem gatilhos no padrão (SX7).

      Se possível poderia detalhar o que não funcionou? Ou se houve algum erro na execução? Que daí eu tento ver se alguém já passou por isso.

      Um grande abraço.

      • cleberfiscal23 disse:

        Bom dia,

        Refazendo aqui, a alteração do campo funcionou, porem a tela aparece como um tela de busca(lupa)

      • cleberfiscal23 disse:

        Bom dia, Dan,

        neste caso, para replicar o campo com sequencial, serial possível ? exemplo, informar na primeira linha 000001 e repetir 000002, 000003….

        • Comentários (site)

          Bom dia Cleber, tudo joia?

          Você gostaria de popular um aCols de forma incremental, seria isso?

          Se for em MVC, você pode usar o AddIncrementField na sua ViewDef, agora se quiser fazer em um For … Next conforme o exemplo do vídeo, recentemente perguntaram no nosso grupo do WhatsApp algo parecido, segue a resposta que demos:

          […]
          Teriam duas formas de você fazer, uma é usando StrZero convertendo a linha atual para texto e a outra é usando a função Soma1 (para caso acontecer de chegar tipo em “99” e ir para “9A”).

          Então a lógica seria:
          1. Ter uma variável declarada antes do For com o inicial da sequência zerado, por exemplo “000”
          2. No for, você incrementa esse sequencial
          3. Ai no mesmo for, você altera sua coluna colocando esse sequencial, algo +- assim:

          //Zera o sequencial e pega o número da coluna
          cSeqAtu := “000”
          nColuna := GDFieldPos(“SEU_CAMPO”)

          //Percorre todas as linhas
          For nLinha := 1 To Len(aCols)
          //Incrementa o item
          cSeqAtu := Soma1(cSeqAtu)

          //Atualiza a coluna na grid
          aCols[nLinha][nColuna] := cSeqAtu
          Next
          […]

          Um grande abraço.

  6. Julio Ribeiro disse:

    Daniel, primeiramente parabéns pelo excelente trabalho e muito obrigado por dividir seus conhecimentos!!

    Essa questão me atendeu parcialmente para a inclusão do centro de custo nos produtos do documento de entrada.

    Existe alguma forma de criar um gatilho que pega a informação digitada pelo usuario no campo D1_CC, na primeira linha e a cada nova linha adicionada ele repita automaticamente essa informação??

    Para funcionar da forma que você ensinou, precisaria tirar a obrigatoriedade do campo no CFG para que ele permita eu incluir todas as linhas e somente o centro de custo no final via outras ações, porém isso abrirá brechas para documentos serem classificados sem o centro de custo e atrapalhará a contabilidade.

    Grato,
    Julio Ribeiro

    • Bom dia Julio, tudo joia?

      Primeiramente obrigado pelo carinho e feedback, é muita gentileza sua.

      Então, daria pra tratar de algumas formas, segue dois cenários que daria para implementar:
      1. Tirar a obrigatoriedade do campo D1_CC, nisso fazer o ponto de entrada MT100TOK, e nele percorrer o aCols e validar, se existir alguma linha que não tem o campo D1_CC preenchido, ai você aborta a operação

      ou

      2. Se quiser permanecer com a obrigatoriedade, daria para criar um gatilho do campo D1_COD para o D1_CC, e validar algo como, se for a partir do segundo item (D1_ITEM maior que 1), você puxa o D1_CC do item 1 e joga na regra do gatilho (algo como aCols[1][GDFieldPos(“D1_CC”)]), isso vai fazer com que o usuário ao colocar o produto, se tiver CC na linha 1, ele já vai disparar o gatilho preenchendo as próximas linhas

      Tenha uma ótima e abençoada quinta feira.

      Um forte abraço.

  7. JULIO RIBEIRO disse:

    Mestre muito obrigado, fiz o gatilho da seguinte forma e “funcionou”:

    IF(EMPTY(aCols[1][GDFieldPos(“D1_CC”)]),” “,aCols[1][GDFieldPos(“D1_CC”)])

    O problema é que o campo D1_CC também tem um gatilho para o campo D1_CONTA e esse gatilho é somente disparado quando o campo D1_CC é preenchido manualmente.

    Tem como resolver isso??

    Obrigado mais uma vez!!

    • JULIO RIBEIRO disse:

      Outro ponto: Utilizando o código que você mostrou no exemplo (com alguns pequenos ajustes), o gatilho da D1_EC05DB não é disparado (o campo recebe o valor, porém não dispara o gatilho).

      Segue o trecho do código:

      lValidou := .T.
      __ReadVar := “M->” + cCampoLOS
      M->(cCampoLOS) := cLOSNovo

      If !Empty(cVldSisLOS)
      lValidou := &(cVldSisLOS)
      EndIf

      If !Empty(cVldUsrLOS) .And. lValidou
      lValidou := &(cVldUsrLOS)
      EndIf

      If lValidou
      aCols[n][nPosLOS] := cLOSNovo
      If ExistTrigger(cCampoLOS)
      RunTrigger( ;
      2,; //nTipo (1=Enchoice; 2=GetDados; 3=F3)
      n,; //Linha atual da Grid quando for tipo 2
      Nil,; //Não utilizado
      ,; //Objeto quando for tipo 1
      cCampoLOS; //Campo que dispara o gatilho
      )
      EndIf
      EndIf

      e o gatilho também:

      GetAdvFval(“SBM”, {“BM_XCONTA”,”BM_YCONTA”}, xFilial(“SBM”)+SB1->B1_GRUPO, 1, {“”,””} )[IF(ALLTRIM(SD1->D1_EC05DB)==”10″, 1, 2)]

      Obs.: Se eu digitar a informação manualmente no campo D1_EC05DB ele dispara o gatilho e alimenta o campo D1_CONTA.

      Se puder me dar uma luz, ficaria agradecido!!

      • Bom dia Julio, tudo joia?

        Então, quando a linha passasse pelo RunTrigger teoricamente era pra disparar o gatilho, e em seguida disparar os outros, igual é na tela. A ideia seria:

        //define o campo
        cCampo := "M->D1_CC"
        
        //aqui aciona os valids
        //&(no X3_VALID) e &(no X3_VLDUSER)
        
        //aqui dispara o gatilho
        If ExistTrigger(...
           RunTrigger(....
        EndIf
        

        Agora quanto a dúvida do D1_EC05DB, como que está ficando a variável lValidou? Se você colocar um breakpoint na linha do RunTrigger, ele ta caindo nela?

        Tenha um ótimo e abençoado fim de semana.

        Um forte abraço.

Deixe uma resposta

Terminal de Informação