Como fazer uma integração com OneDrive via AdvPL de forma manual

No artigo de hoje, vou mostrar como copiar arquivos gerados via AdvPL (ou até mesmo arquivos que ficam no servidor na Protheus Data) para uma pasta compartilhada do OneDrive.

Antes de começarmos pessoal, vou detalhar abaixo o cenário do cliente:

  • O cliente não possuía a integração paga com a API da Microsoft
  • Então foi preparado uma máquina com uma conta do OneDrive configurada
  • Nesse computador, foi compartilhado uma pasta na rede, dentro da pasta do OneDrive

Agora com esse cenário, vamos a lógica que foi desenvolvida:

  1. Nos jobs que geram os relatórios em PDF na Protheus Data, é acionado a função zOneDrive
  2. Essa função, cria 2 arquivos .bat dentro da Protheus Data, um é para criar uma pasta dentro da pasta compartilhada na rede e o outro é para copiar o relatório, mudando de nome
  3. Todas as tentativas de realizar a cópia via rede (seja com WaitRunSrv, com XCOPY, etc), falharam (talvez devido ao Firewall do cliente). Então ao invés de acionar a cópia via AdvPL, foi criado um código em Java que aciona os dois arquivos bat criados no passo 2
  4. Via Agendador do Windows, foi agendado para rodar esse .jar duas vezes ao dia

Abaixo o código fonte em AdvPL:

//Bibliotecas
#Include "TOTVS.ch"
   
/*/{Protheus.doc} User Function zOneDrive
Função que copia um relatório local da Protheus Data para uma pasta no OneDrive
@type  Function
@author Atilio
@since 02/05/2022
/*/
   
User Function zOneDrive(dDataRef, cDirOrig, cArqOrig, cArqDest)
    Local aArea     := FWGetArea()
    Local cPastaOne := SuperGetMV("MV_X_ONEDR", .F., "\2.168.70.209\relatorios\")
    Local cDirTmp   := "\x_temp\onedrive\"
    Local cArqBat   := "1_" + dToS(Date()) + "_" + StrTran(Time(), ":", "-") + "_pasta_onedrive.bat"
    Local cArqBat2  := "2_" + dToS(Date()) + "_" + StrTran(Time(), ":", "-") + "_copia_onedrive.bat"
    Local cComandos := ""
    Local cDirBase  := GetSrvProfString("RootPath", "")
    Default dDataRef := DaySub(Date(), 1)
    Default cDirOrig := ""
    Default cArqOrig := ""
    Default cArqDest := ""
   
    //Somente se tiver as quatro pastas
    If ! Empty(cDirOrig) .And. ! Empty(cArqOrig) .And. ! Empty(cArqDest)
        //Somente se o arquivo existir na origem
        If File(cDirOrig + cArqOrig)
            cArqDest := FWNoAccent(cArqDest)
   
            //Monta o diretório de destino - 202205 (Maio de 2022)\
            cDirDest := SubStr(dToS(dDataRef), 1, 6) + " (" + MesExtenso(dDataRef) + " de " + cValToChar(Year(dDataRef)) + ")\"
            If ! ExistDir(cPastaOne + cDirDest)
                cComandos := 'mkdir "' + cPastaOne + cDirDest + '"' + CRLF
            EndIf
   
            //Dia 01\
            cDirDest += "Dia " + StrZero(Day(dDataRef), 2) + "\"
            If ! ExistDir(cPastaOne + cDirDest)
                cComandos := 'mkdir "' + cPastaOne + cDirDest + '"' + CRLF
            EndIf
   
            //Se houver comandos, cria o bat
            If ! Empty(cComandos)
                //Caso o arquivo ja exista, será excluido
                If File(cDirTmp + cArqBat)
                    FErase(cDirTmp + cArqBat)
                EndIf
                MemoWrite(cDirTmp + cArqBat, cComandos)
            EndIf
   
            //Bat que copia o arquivo e renomeia
            cComandos := ''
            cComandos += 'XCOPY "' + cDirBase + cDirOrig + cArqOrig+ '" "' + cPastaOne + cDirDest + '" /y' + CRLF
            cComandos += 'RENAME "' + cPastaOne + cDirDest + cArqOrig + '" "' + cArqDest + '"' + CRLF
            cComandos += 'timeout 2' + CRLF
            MemoWrite(cDirTmp + cArqBat2, cComandos)
   
            Sleep(5000)
        EndIf
    EndIf
   
    FWRestArea(aArea)
Return

E abaixo o código fonte em Java:

import java.io.File;
import java.io.IOException;
   
public class PExecCopy {
   
    /*
     * Author: Daniel Atilio
     * References:
     *  Get Files - https://www.tutorialspoint.com/how-to-get-list-of-all-files-folders-from-a-folder-in-java
     *  File Contains ".bat" - https://stackoverflow.com/questions/17134773/to-check-if-string-contains-particular-word
     *  Run Batch - https://stackoverflow.com/questions/615948/how-do-i-run-a-batch-file-from-my-java-application
     *  Delete Files - https://www.geeksforgeeks.org/delete-file-using-java/
     */
       
    public static void main(String[] args) {
        String folder = "D:\\TOTVS\\Protheus_Data\\x_temp\\onedrive\\";
        String fullFile = "";
        String search  = ".bat";
           
        //Creating a File object for directory
        File directoryPath = new File(folder);
             
        //List of all files and directories
        String contents[] = directoryPath.list();
        System.out.println("List of files and directories in the specified directory:");
        for(int i=0; i<contents.length; i++) {
            fullFile = folder + contents[i];
            System.out.println(fullFile);
               
            //Validate file is .bat
            if ( fullFile.toLowerCase().indexOf(search.toLowerCase()) != -1 ) {
               
                try{    
                    Process p = Runtime.getRuntime().exec(fullFile);
                    p.waitFor();
       
                }catch( IOException ex ){
                    //Validate the case the file can't be accesed (not enought permissions)
                    System.out.println("Failed to run batch #1");
       
                }catch( InterruptedException ex ){
                    //Validate the case the process is being stopped by some external situation
                    System.out.println("Failed to run batch #2");
       
                }
                   
                   
                //Delete file
                File file = new File(fullFile);
                   
                if (file.delete()) {
                    System.out.println("File deleted successfully");
                }
                else {
                    System.out.println("Failed to delete the file");
                }
            }
        }
   
    }
   
}

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.

Deixe uma resposta

Terminal de Informação