Solved

Mass Download Attachments from Acumatica

  • 3 February 2023
  • 4 replies
  • 456 views

Userlevel 7
Badge +8

Hello Community,

Does anyone have any experience with mass downloading attachments from Acumatica? I have done a little bit of digging and seems “UploadFileInq” is the graph that manages the files/attachments and the “GetFile” action handles single file downloading. The issue I am facing is I do not see the real implementation code for the graph just declaring the views, filters, actions, and handlers. For example, I see the “GetFile” action but I do not see its method code. Or I see “FilesFilter_RowUpdated” handler but I do not see any code in it but for sure there should be because when we change the filter parameters the result grid changes. Or I can not see any Files select statement tied to the current value of the filters.

I was wondering if this is one of those graphs Acumatica doesn’t like to be accessible for customizations! Any thought or direction to the right path is greatly appreciated.

Ideally, I would like to open “File Download” dialog once to get the download path and download all files that meet the filter criteria.

icon

Best answer by Brian Stevens 4 February 2023, 00:25

View original

4 replies

Userlevel 6
Badge +4

You may want to introduce a processing screen to select the files of interest and then act on those files.

I once used the following code to extract files from the database and dump to a folder on the server.  You would need to modify for your purposes, but it gives some insight into how to get files.

#region ExportAttachments
public static void ExportAttachments(Guid? fromNoteID, string outFolder)
{
UploadFileMaintenance upload = PXGraph.CreateInstance<UploadFileMaintenance>();

PXResultset<NoteDoc> list = GetFiles(fromNoteID);
foreach (NoteDoc doc in list)
{
PX.SM.FileInfo sourceFile = upload.GetFile((Guid)doc.FileID);

if (!Directory.Exists(outFolder)) Directory.CreateDirectory(outFolder);

string pathOfFile = Path.GetDirectoryName(outFolder) + "\\" + sourceFile.Name;
File.WriteAllBytes(pathOfFile, sourceFile.BinData);
PXTrace.WriteInformation(pathOfFile);
}
}
#endregion

#region GetFiles
public PXResultset<NoteDoc> GetFiles(Guid? noteID)
{
var list = SelectFrom<NoteDoc>
.Where<NoteDoc.noteID.IsEqual<@P.AsGuid>>
.View.Select(this, noteID);
return list;
}
#endregion

Notice how files are linked to objects such as items throuhg NoteDoc.  From NoteDoc, you get the file via GetFile in the UploadFileMaintenance graph by FileID stored in a PX.SM.FileInfo object.  From that object, the actual file data is contained within the BinData field.

Userlevel 7
Badge +8

@Brian Stevens Thanks for the insight.

It seems the ExportAttachments doesn’t like the GetFile non-static method and if I make the GetFile static am not able to pass the Base graph to select statement. Was there a trick to make this work?

 

Also, don’t you possibly have the processing screen code handy so that I modify it instead of rewriting it?

Userlevel 6
Badge +4

I extracted the code for GetFiles from the graph I had it in.  It was intended to be code samples, so you’d need to tweak it.

Try this.  I simply added a parameter to pass a graph and adjusted accordingly.

#region ExportAttachments
public static void ExportAttachments(Guid? fromNoteID, string outFolder)
{
UploadFileMaintenance upload = PXGraph.CreateInstance<UploadFileMaintenance>();

PXResultset<NoteDoc> list = GetFiles(upload, fromNoteID);
foreach (NoteDoc doc in list)
{
PX.SM.FileInfo sourceFile = upload.GetFile((Guid)doc.FileID);

if (!Directory.Exists(outFolder)) Directory.CreateDirectory(outFolder);

string pathOfFile = Path.GetDirectoryName(outFolder) + "\\" + sourceFile.Name;
File.WriteAllBytes(pathOfFile, sourceFile.BinData);
PXTrace.WriteInformation(pathOfFile);
}
}
#endregion

#region GetFiles
public static PXResultset<NoteDoc> GetFiles(PXGraph graph, Guid? noteID)
{
var list = SelectFrom<NoteDoc>
.Where<NoteDoc.noteID.IsEqual<@P.AsGuid>>
.View.Select(graph, noteID);
return list;
}
#endregion

This is my processing screen, with some names changed.

using PX.Data;
using System;

namespace MyNamespace
{
public class CUSTMyFileProcess : PXGraph<CUSTMyFileProcess>
{
#region Filters
public PXCancel<CUSTMyItem> Cancel;
public PXProcessing<CUSTMyItem> Items;
#endregion

#region Constructor
public CUSTMyFileProcess()
{
Items.SetProcessCaption("Export");
Items.SetProcessAllCaption("Export All");
Items.SetProcessDelegate<CUSTMyItemEntry>(
delegate (CUSTMyItemEntry graph, CUSTMyItem item)
{
try
{
graph.Clear();
graph.Export(item, true);
}
catch (Exception e)
{
PXProcessing<CUSTMyItem>.SetError(e);
}
});
}
#endregion

#region Overridden Properties
public override bool IsDirty => false;
#endregion

}
}

 

Userlevel 7
Badge +8

@Brian Stevens really appreciated 

Reply


About Acumatica ERP system
Acumatica Cloud ERP provides the best business management solution for transforming your company to thrive in the new digital economy. Built on a future-proof platform with open architecture for rapid integrations, scalability, and ease of use, Acumatica delivers unparalleled value to small and midmarket organizations. Connected Business. Delivered.
© 2008 — 2024  Acumatica, Inc. All rights reserved