Maximo

 View Only
  • 1.  Bulk download the attachments

    Posted Mon May 15, 2023 06:16 PM

    Hi Community,

    Please advise if there is a way to download all or multiple attachments, uploaded against a WO, together from Maximo UI.

    Currently, we can download one attachment at a time by clicking on the attachment name from View Attachments dialog box, but it becomes bit cumbersome for end users when there are few dozens of attachments against a workorder, and they need to analyse them by downloading it one by one. I am trying to find if there is any way without the customization. 
    Please note that we are not using Maximo mobile or anywhere solution. 

    Thanks



    ------------------------------
    Gaurav
    ------------------------------


  • 2.  RE: Bulk download the attachments

    Posted Wed May 17, 2023 08:03 AM

    Hi Gaurav,

    Unfortunately there is no way to download attachments in bulk but you can try to add a button on the screen say "Download All Attachments" and run an automation script which will read all the attached documents, fetch it from server and download on local drive. Easiear said than done, this would need a POC to check if the required access is is there or not to read the docs and fetch it on local drive.



    ------------------------------
    Suhas Joshi
    ------------------------------



  • 3.  RE: Bulk download the attachments

    Posted Mon May 22, 2023 07:52 AM

    You can do this. Trigger an email using a Maximo communication template with the appropriate attachment folders on the tab selected for all WO's or whatever. I send them to myself and move them into a separate folder using rules.. I have then written VB that extracts the attachments and puts them in a folder. See below. Locations removed for security/privacy. The replace helps with filenames that aren't valid.

    Sub Attachment_SaveAttchments()
        Dim objMail As Outlook.MailItem
        Dim objWsShell As Object
        Dim strTempFolder As String
        Dim objAttachments As Outlook.Attachments
        Dim objAttachment As Attachment
        Dim strFileName As String
        
    Set myNameSpace = Application.GetNamespace("MAPI")
    Set myFolder = myNameSpace.GetDefaultFolder(olFolderInbox)
    Set myNewFolder = myFolder.Folders("VF Docs")
    Set emailList = myNewFolder.Items
     
    strTempFolder = "file location"
     
    For Each objMail In emailList
     
        Set objAttachments = objMail.Attachments    
      
        If objAttachments.Count > 0 Then        
            
            For Each objAttachment In objAttachments
            strFileName = objMail.Subject
            strFileName = Replace(strFileName, "/", "-")
            strFileName = Replace(strFileName, ",", "-")
            strFileName = Replace(strFileName, ":", " ")
            strFileName = Replace(strFileName, "_", " ")
            
            docName = objAttachment.FileName
            docName = Replace(docName, ",", "-")
            docName = Replace(docName, "/", "-")
            docName = Replace(docName, ":", " ")
            docName = Replace(docName, "_", " ")
            
            fileNameLoc = strTempFolder & strFileName & " " & docName
            objAttachment.SaveAsFile fileNameLoc
            Next
            
        End If
    Next
     
    End Sub


    ------------------------------
    Andy Winter
    Salisbury Group
    01908 208472
    ------------------------------



  • 4.  RE: Bulk download the attachments

    Posted Thu June 08, 2023 03:21 PM

    Hi Gaurav I made this script to export PM's attachments to a specific folder on another server.

    HashMap = Java.type('java.util.HashMap');
    MXServer = Java.type('psdi.server.MXServer');

    var dirDest = "<Folder target where you'll put the files>";

    var libreria = new HashMap();
    libreria.put('service',service);

    //var i = 0;
    var strPath = null;
    var strPathOrig = null;
    var archivo = null;
    var dirOrig = null;
    var userInfo = MXServer.getMXServer().getSystemUserInfo();

    PMSet = MXServer.getMXServer().getMboSet("PM",userInfo);
    PMSet.setWhere("PM.STATUS = 'ACTIVO'");
    PMSet.reset();
    pm = PMSet.moveFirst();

    while(pm){
        doclinkSet = pm.getMboSet("DOCLINKSCIC");
        doclink = doclinkSet.moveFirst();
        
        while(doclink){
            docinfoSet = doclink.getMboSet("DOCINFO");
            docinfo = docinfoSet.getMbo(0);
        
            strPathOrig = docinfo.getString("URLNAME");
            strPath = strPathOrig.split("\\");
            archivo = strPath[strPath.length-1];
            dirOrig = strPathOrig.replace("\\","\\\\");
        
            resultado = service.invokeScript("SCRIPTUTILS").copyFiles(dirOrig, dirDest + archivo);
            service.log_info(resultado);
        
            doclink = doclinkSet.moveNext();
        }
        pm = PMSet.moveNext();
        
    }

    Note: SCRIPUTILS is a script that I use as a utils library.

    Best Regards



    ------------------------------
    Pablo Condoleo
    ------------------------------



  • 5.  RE: Bulk download the attachments
    Best Answer

    IBM Champion
    Posted Thu June 08, 2023 05:25 PM

    Okay, let's do this properly. 

    Below is a script that you can invoke from a Launch in Context that will download the attachments for the specify object and record id. Assuming you named the script SHARPTREE.DOWNLOAD.ATTACHMENTS (as in the example) and you are this for the Work Order Tracking application in the launch in context URL you will put https://yourmaximoserver/maximo/oslc/script/SHARPTREE.DOWNLOAD.ATTACHMENTS?id={workorderid}&object=WORKORDER

    This supports both local files and S3 storage.

    Note: You can test this manually by substituting the workorderid (not wonum) and using your browser directly.

    The {workorderid} will be replaced by the framework with the current work order id and this will let the script find your record and download the archive.

    If you use the VS Code extension you can directly deploy this script, which will save you some time and effort.

    https://marketplace.visualstudio.com/items?itemName=sharptree.maximo-script-deploy

    This is effectively following the same pattern we used for the Excel export, so you might want to check that out for more details or context for using the Launch in Context.

    https://www.sharptree.io/blog/2023/2023-05-22-excel/

    If you have any questions feel free to reach out.


    Cheers,
    Jason

    COSApi = Java.type("com.ibm.tivoli.maximo.cos.COSApi");
    
    BufferedOutputStream = Java.type("java.io.BufferedOutputStream");
    ByteArrayOutputStream = Java.type('java.io.ByteArrayOutputStream');
    File = Java.type("java.io.File");
    
    Files = Java.type("java.nio.file.Files");
    Paths = Java.type("java.nio.file.Paths");
    
    ZipOutputStream = Java.type("java.util.zip.ZipOutputStream");
    ZipEntry = Java.type("java.util.zip.ZipEntry");
    
    MicUtil = Java.type("psdi.iface.mic.MicUtil");
    
    MXServer = Java.type('psdi.server.MXServer');
    
    System = Java.type("java.lang.System");
    
    main();
    
    function main() {
        var lookupSet;
        try {
            var mbo;
            if (typeof request !== undefined) {
                var id = request.getQueryParam("id");
                var objectName = request.getQueryParam("object");
                lookupSet = MXServer.getMXServer().getMboSet(objectName, userInfo);
                mbo = lookupSet.getMboForUniqueId(id);
            }
    
            if (typeof mbo !== 'undefined' && mbo) {
                // if the Mbo has a DOCLINKS relationship we can get all the attachments.
                if (mbo.getThisMboSet().getMboSetInfo().getRelationInfo("DOCLINKS")) {
                    var docLinksSet = mbo.getMboSet("DOCLINKS");
                    var paths = [];
    
                    var docLink = docLinksSet.moveFirst();
    
                    while (docLink) {
                        paths.push(docLink.getString("DOCINFO.URLNAME"));
                        docLink = docLinksSet.moveNext();
                    }
    
                    if (paths.length > 0) {
                        zipFile = zipFiles(paths);
                        downloadZipFile(zipFile, "attachments.zip",request);
                    }
                }
            }
        } finally {
            close(lookupSet);
        }
    }
    
    /**
     * Fetch and zip the file paths. Handles both local and S3 storage.
     * @param {Array[String]} files an array of paths to the attached files.
     * @returns An byte array representing the resulting zip file.
     */
    function zipFiles(files) {
        var bucketName = MicUtil.getProperty("mxe.cosbucketname");
    
        var output = new ByteArrayOutputStream();
        var zipOutput = new ZipOutputStream(new BufferedOutputStream(output));
            files.forEach(function zipFile(file){
                var content;
                if(file.startsWith("cos")){
                    var fileName = (new File(file)).getName();
                    content = new COSApi().getFile(bucketName, fileName);;
                }else{
                    content = Files.readAllBytes(Paths.get(file));
                }
    
                var fileName  = (new File(file)).getName();
                var zipEntry = new ZipEntry(fileName);
                zipOutput.putNextEntry(zipEntry);
                zipOutput.write(content, 0, content.length);
                zipOutput.flush();
            });
    
        zipOutput.flush();
        zipOutput.close();
        
        return output.toByteArray();    
    }
    
    /**
     * Close and clean up the MboSet resources.
     * @param {MboSet} set the MboSet to close and clean up.
     */
    function close(set) {
        if (set) {
            set.close();
            set.cleanup();
        }
    }
    
    /**
     * Download the zip file to the script request HTTP output.  This only works when the script is invoked directly.
     * @param {byte[]} zipFile The byte array representing the POI workbook,
     * @param {String} fileName Optional name of the file to export.  If not provided "export.xlsx" is used.
     * @param {com.ibm.tivoli.maximo.oslc.provider.OslcRequest} oslcRequest optional OslcRequest object if an implicit request variable is unavailable.
     */
    function downloadZipFile(zipFile, fileName, oslcRequest) {
    
        if (typeof request === 'undefined' && !oslcRequest) {
            throw new Error('The downloadZipFile function can only be called from a direct script invocation with the "request" implicit variable available or with the oslcRequest provided.');
        }
    
        if (!zipFile) {
            throw new Error('A zip file is required to export.');
        }
    
        var response = (typeof request === 'undefined') ? oslcRequest.getHttpServletResponse() : request.getHttpServletResponse();
        response.setBufferSize(0);
        response.setContentType("application/zip");
        response.setHeader("content-disposition", 'attachment; filename="' + (fileName ? fileName : 'attachments.zip') + '"');
        response.getOutputStream().write(zipFile);
    
        response.flushBuffer();
    }
    
    var scriptConfig = {
        "autoscript": "SHARPTREE.DOWNLOAD.ATTACHMENTS",
        "description": "Sharptree script to download all attachments.",
        "version": "1.0.0",
        "active": true,
        "logLevel": "ERROR"
    };


    ------------------------------
    Jason VenHuizen
    https://sharptree.io
    https://opqo.io
    ------------------------------



  • 6.  RE: Bulk download the attachments

    Posted Fri June 09, 2023 08:46 AM

    Hi Jason thank you it's a nice option to export attachments. Because I've never used Launch in Context in Maximo so I'll be looking at how to import a specific attachment when an update of the file is needed.

    Thanks and Regards



    ------------------------------
    Pablo Condoleo
    ------------------------------



  • 7.  RE: Bulk download the attachments

    IBM Champion
    Posted Thu June 08, 2023 08:39 PM

    Pablo,

    When you get the PMSet you are doing so as the system user (maxadmin) and are then not closing the set.  Because you are using the system user the user session will never terminate and therefore the set will remain open and cause a memory leak.  It is good practice to place your MboSets in a try / finally to close and cleanup after you are done using them.  You may also consider not using the system user if possible to at least have the objects cleaned up when the session closes and to avoid security issues as well.  

    https://www.sharptree.io/blog/2021/2021-11-22-close-things/

    One other thing you may want to consider is using PMSet.setFlag(MboConstants.DISCARDABLE, true); to mark the Mbos discardable so they aren't retained as you iterate over them this will further reduce your memory footprint.



    ------------------------------
    Jason VenHuizen
    https://sharptree.io
    https://opqo.io
    ------------------------------