Como imprimir uma tabela dinamicamente em um modelo DOT com AdvPL

No artigo de hoje, vou demonstrar como criar linhas em uma tabela num modelo dot via AdvPL.

Há muito tempo, aproximadamente em 2013, eu precisei fazer esse processo de criar linhas dinamicamente em uma tabela via integração com modelo dot. Na época, os programadores na consultoria tinham me ajudado a chegar na solução.

Porém com o tempo, acabei perdendo o script da macro do Word, eis que recentemente, estava conversando com meu amigo Bruno Vinícius ( LinkedIn ), e com a ajuda dele, consegui montar novamente a macro, e esse exemplo que segue abaixo.

Antes de começar o tutorial, se você não conhece a integração com modelos dot, recomendo a leitura do artigo Gerando um arquivo do Word pelo AdvPL usando integração com Modelos DOT.

  1. Abra o Word, insira as variáveis (conforme link explicado no artigo acima), e depois clique em Inserir > Tabela, coloque o número de colunas desejada e pelo menos 2 linhas

Inserindo uma tabela

  1. Posicione o cursor do mouse, na segunda linha, e na primeira coluna, conforme print abaixo

Posicionando na primeira coluna da segunda linha

  1. Vá em Inserir > Links > Indicador (em inglês Bookmark)

Inserindo bookmark

  1. Dê um nome para o indicador, no nosso exemplo, iremos chamar de tabItens

Colocando um nome para o bookmark

  1. Agora vá em Exibir > Macros > Exibir Macros

Acessando as Macros

  1. Digite um nome para a Macro, iremos repetir o nome usado no passo 4, e então clique no botão Criar

Dando um nome para a Macro

  1. Cole o comando abaixo na tela de código da Macro (esse código que irá criar as linhas na tabela, juntamente com a criação de DocVariables dentro das células da tabela)
Sub tabItens()
	' Cria as variáveis
	Dim Line As Integer
	Dim QtdeLines As Integer
	Dim Campo1 As String
	Dim Campo2 As String
	Dim Campo3 As String

	' Posiciona no BookMark
	Selection.GoTo What:=wdGoToBookmark, Name:="tabItens"
	Selection.Find.ClearFormatting
	With Selection.Find
		.Text = ""
		.Replacement.Text = ""
		.Forward = True
		.Wrap = wdFindContinue
		.Format = False
		.MatchCase = False
		.MatchWholeWord = False
		.MatchWildcards = False
		.MatchSoundsLike = False
		.MatchAllWordForms = False
	End With

	' Busca a quantidade de linhas definida em QtdePro
	QtdeLines = Val(ActiveDocument.Variables.Item("QtdePro").Value)
	
	' Percorre de 1 até o número de linhas definida
	For Line = 1 To QtdeLines
		' Se for a coluna 1, preenche o valor com uma docvariable e pula para a coluna da direita
		Campo1 = "DOCVARIABLE ITEM1" & Trim(Str(Line))
		Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:=Campo1, PreserveFormatting:=True
		Selection.MoveRight Unit:=wdCell
		
		' Se for a coluna 2, preenche o valor com uma docvariable e pula para a coluna da direita
		Campo2 = "DOCVARIABLE ITEM2" & Trim(Str(Line))
		Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:=Campo2, PreserveFormatting:=True
		Selection.MoveRight Unit:=wdCell
		
		' Se for a coluna 3, preenche o valor com uma docvariable
		Campo3 = "DOCVARIABLE ITEM3" & Trim(Str(Line))
		Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:=Campo3, PreserveFormatting:=True
		
		' Se a linha atual for menor que a última linha, pula para a direita (irá incluir uma nova linha)
		If Line < QtdeLines Then
			Selection.MoveRight Unit:=wdCell
		End If
	Next
End Sub
  1. A tela irá ficar com os comandos, conforme print abaixo

Informando o código da macro

  1. Clique no botão salvar na macro

Salvando a Macro

  1. Agora, no Word, clique em Salvar Como, escolha uma pasta, e coloque o tipo como Modelo do Word. Esse arquivo, copie para dentro da Protheus Data, no nosso caso, iremos chamar de modelo.dotx e irá ficar dentro da pasta \x_dots\

Salvando o modelo DOT

  1. Compile a função abaixo em AdvPL, e faça o teste acionando ela, note que ela irá popular as variáveis e depois irá executar a macro para criar as linhas
//Bibliotecas
#Include "TOTVS.ch"
#Include "TopConn.ch"

/*/{Protheus.doc} User Function zTstDot
Função de teste, para mostrar como inserir linhas dinamicamente em um modelo dot
@type  Function
@author Atilio
@since 29/05/2021
/*/

User Function zTstDot(param_name)
    Local aArea := GetArea()
    Local cArquivo := "modelo.dotx"
    Local cArqSrv := "\x_dots\" + cArquivo
    Local cDirTmp := GetTempPath()
    Local nHandWord
    Local nItens := 0
    Local cQuery := ""

    //Copia o arquivo da protheus data para o pc do usuário
    CpyS2T(cArqSrv, cDirTmp)

    //Cria um ponteiro e já chama o arquivo
    nHandWord := OLE_CreateLink()
    OLE_NewFile(nHandWord, cDirTmp + cArquivo)
    
    //Setando o conteúdo das DocVariables
    OLE_SetDocumentVar(nHandWord, "DataHoje", dToC(Date()))
    OLE_SetDocumentVar(nHandWord, "HoraHoje", Time())
    OLE_SetDocumentVar(nHandWord, "Autor", UsrRetName(RetCodUsr()))

    //Busca 10 produtos que sejam do tipo PA e que não estejam bloqueados
    cQuery += " SELECT TOP 10 " + CRLF
    cQuery += "     B1_COD, " + CRLF
    cQuery += "     B1_DESC, " + CRLF
    cQuery += "     B1_UM " + CRLF
    cQuery += " FROM " + CRLF
    cQuery += "     " + RetSQLName("SB1") + " SB1 " + CRLF
    cQuery += " WHERE " + CRLF
    cQuery += "     B1_FILIAL = '" + FWxFilial('SB1') + "' " + CRLF
    cQuery += "     AND B1_MSBLQL != '1' " + CRLF
    cQuery += "     AND B1_TIPO = 'PA' " + CRLF
    cQuery += "     AND SB1.D_E_L_E_T_ = ' ' " + CRLF
    cQuery += " ORDER BY " + CRLF
    cQuery += "     B1_COD " + CRLF
    TCQuery cQuery New Alias "QRY_SB1"

    //Enquanto houver dados na query
    While ! QRY_SB1->(EOF())
        //Incrementa o total de itens
        nItens++

        //Define as variaveis das celulas 1, 2, 3 da linha atual no documento
        OLE_SetDocumentVar(nHandWord, 'ITEM1' + cValToChar(nItens), QRY_SB1->B1_COD )
        OLE_SetDocumentVar(nHandWord, 'ITEM2' + cValToChar(nItens), QRY_SB1->B1_DESC )
        OLE_SetDocumentVar(nHandWord, 'ITEM3' + cValToChar(nItens), QRY_SB1->B1_UM )

        QRY_SB1->(dbSkip())
    EndDo
    QRY_SB1->(DbCloseArea())

    //Define a quantidade de produtos e executa a macro para criar as linhas
    OLE_SetDocumentVar(nHandWord, 'QtdePro', cValToChar(nItens))
	OLE_ExecuteMacro(nHandWord, "tabItens")

    //Atualizando campos
    OLE_UpdateFields(nHandWord)
    
    //Monstrando um alerta
    MsgAlert('O arquivo gerado foi <b>Salvo</b>?<br>Ao clicar em OK o Microsoft Word será <b>fechado</b>!','Atenção')
    
    //Fechando o arquivo e o link
    OLE_CloseFile(nHandWord)
    OLE_CloseLink(nHandWord)

    RestArea(aArea)
Return
  1. Abaixo um print do resultado do word

Exemplo de relatório gerado via AdvPL

Bom pessoal, por hoje é só.

Abraços e até a próxima.

Dan Atilio (Daniel Atilio)
Especialista em Engenharia de Software pela FIB. Entusiasta de soluções Open Source. E blogueiro nas horas vagas.

Deixe uma resposta