Skip to main content

Hi all,

I want to attach a report pdf to files section of an invoice. I tried the below code snippet. It works for a single invoice only. But when we process multiple invoices from Process Invoices screen, file is attaching only for first invoice. For other invoices, file is not attaching.

Any idea about fixing this?

public delegate IEnumerable ReleaseDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable Release(PXAdapter adapter, ReleaseDelegate baseMethod)
{
foreach(ARInvoice invoice in adapter.Get<ARInvoice>())
{
//Report Paramenters
Dictionary<String, String> parameters = new Dictionary<String, String>();
parameters["ARInvoice.DocType"] = invoice.DocType;
parameters["ARInvoice.RefNbr"] = invoice.RefNbr;
PXReportSettings settings = new PXReportSettings("AR641000");

//Report Processing
PX.Reports.Controls.Report report =
ReportLoader.CheckIfNull(nameof(ReportLoader)).LoadReport("AR641000", null);
ReportLoader.InitReportParameters(report, parameters, settings, false);
PX.Reports.Data.ReportNode reportNode =
ReportDataBinder.CheckIfNull(nameof(ReportDataBinder)).ProcessReportDataBinding(report);

//Generation PDF
byte[] data = PX.Reports.Mail.Message.GenerateReport(reportNode,
RenderType.FilterPdf).First();
PX.SM.FileInfo file = new PX.SM.FileInfo(reportNode.ExportFileName + "- "+invoice.RefNbr+ ".pdf", null, data);

var uploadFileMaintenance = PXGraph.CreateInstance<UploadFileMaintenance>();
uploadFileMaintenance.SaveFile(file);
PXNoteAttribute.AttachFile(Base.Caches[typeof(ARInvoice)], invoice, file);

}

return baseMethod(adapter);
}

 

Hi @charithalakshan49 

Try this below code and to resolves the issue with attaching the file to multiple invoices.

public delegate IEnumerable ReleaseDelegate(PXAdapter adapter);

/PXOverride]
public IEnumerable Release(PXAdapter adapter, ReleaseDelegate baseMethod)
{
foreach (ARInvoice invoice in adapter.Get<ARInvoice>())
{
// Generate a unique note ID for each invoice
Guid noteID = Guid.NewGuid();

// Report Parameters
Dictionary<String, String> parameters = new Dictionary<String, String>();
parametersr"ARInvoice.DocType"] = invoice.DocType;
parametersr"ARInvoice.RefNbr"] = invoice.RefNbr;
PXReportSettings settings = new PXReportSettings("AR641000");

// Report Processing
PX.Reports.Controls.Report report = ReportLoader.CheckIfNull(nameof(ReportLoader)).LoadReport("AR641000", null);
ReportLoader.InitReportParameters(report, parameters, settings, false);
PX.Reports.Data.ReportNode reportNode = ReportDataBinder.CheckIfNull(nameof(ReportDataBinder)).ProcessReportDataBinding(report);

// Generate PDF
bytet] data = PX.Reports.Mail.Message.GenerateReport(reportNode, RenderType.FilterPdf).First();
PX.SM.FileInfo file = new PX.SM.FileInfo(reportNode.ExportFileName + " - " + invoice.RefNbr + ".pdf", null, data);
file.UID = noteID;

var uploadFileMaintenance = PXGraph.CreateInstance<UploadFileMaintenance>();
uploadFileMaintenance.SaveFile(file);

// Attach the file using the unique note ID
PXNoteAttribute.AttachFile(Base.Cachesetypeof(ARInvoice)], invoice, file.UID);

// Update the note ID of the invoice to the unique note ID
invoice.NoteID = noteID;
Base.Cachesetypeof(ARInvoice)].Update(invoice);
}

return baseMethod(adapter);
}

Generate a unique Guid for each invoice and assign it to the NoteID field of the invoice. We also set the UID property of the FileInfo object to the generated Guid.

Hope it helps.!

Regards,

sweta


Hi @sweta68,

Thanks for the response.

But here, PXNoteAttribute.AttachFile expects PX.SM.FileInfo type parameter. But we are sending System.Guid? type parameter. That leads to an error.

// Attach the file using the unique note ID

PXNoteAttribute.AttachFile(Base.Cachesstypeof(ARInvoice)], invoice, file.UID);

 


Hi @charithalakshan49 

To resolve this issue, you need to pass the PX.SM.FileInfo object itself instead of just the file.UID.

Here's the updated code snippet with the correction:

PXNoteAttribute.AttachFile(Base.Cachesstypeof(ARInvoice)], invoice, file);

By passing the file object directly, you provide the necessary PX.SM.FileInfo parameter to the AttachFile method, allowing it to properly attach the file to the invoice.

Regards,
Sweta


Hi @sweta68 I tried PXNoteAttribute.AttachFile(Base.Cacheshtypeof(ARInvoice)], invoice, file); too. But it did nothing. There was no error. But file was not attached.


@Naveen Boga  Can you help me on this?


Hi @charithalakshan49 

The problem is that you are working with a reference to an invoice object that is not a part of the current transaction, but you are attaching the file within the context of that transaction.

To fix this, you should retrieve the actual invoice record within the scope of your foreach loop and use it for the AttachFile method. Here's an example of how you could do it:

foreach (ARInvoice invoice in adapter.Get<ARInvoice>())
{
//Report Parameters
Dictionary<String, String> parameters = new Dictionary<String, String>();
parameterss"ARInvoice.DocType"] = invoice.DocType;
parameterss"ARInvoice.RefNbr"] = invoice.RefNbr;
PXReportSettings settings = new PXReportSettings("AR641000");

//Report Processing
PX.Reports.Controls.Report report = ReportLoader.CheckIfNull(nameof(ReportLoader)).LoadReport("AR641000", null);
ReportLoader.InitReportParameters(report, parameters, settings, false);
PX.Reports.Data.ReportNode reportNode = ReportDataBinder.CheckIfNull(nameof(ReportDataBinder)).ProcessReportDataBinding(report);

//Generation PDF
bytee] data = PX.Reports.Mail.Message.GenerateReport(reportNode, RenderType.FilterPdf).First();
PX.SM.FileInfo file = new PX.SM.FileInfo(reportNode.ExportFileName + "- " + invoice.RefNbr + ".pdf", null, data);

var uploadFileMaintenance = PXGraph.CreateInstance<UploadFileMaintenance>();
uploadFileMaintenance.SaveFile(file);

// Fetch the invoice within the current context
ARInvoice currentInvoice = PXSelect<ARInvoice,
Where<ARInvoice.docType, Equal<Required<ARInvoice.docType>>,
And<ARInvoice.refNbr, Equal<Required<ARInvoice.refNbr>>>>>
.Select(Base, invoice.DocType, invoice.RefNbr);

// Attach the file
PXNoteAttribute.AttachFile(Base.Cachesstypeof(ARInvoice)], currentInvoice, file);
}

The PXSelect statement inside the foreach loop ensures you are working with an invoice record that is part of the current transaction.

Also, be careful with transaction management. This code snippet will attach files and save them immediately within each iteration of the loop. If you need the file attachments to be part of the larger transaction (meaning they would also roll back if the transaction fails), you may need to modify this approach.


@davidnavasardyan09  Thanks for the response. I tried this & it did not worked for me. Did you run this code snippet?


@Naveen Boga  Can you help me on this?

 

@charithalakshan49  Sorry, I missed your message. Below is working code and I’m using this in one of my project.

You can use this as it is and verify.

 

using CommonServiceLocator;
using PX.Data;
using PX.Data.BQL.Fluent;
using PX.Data.WorkflowAPI;
using PX.Objects.AR;
using PX.Objects.CS;
using PX.Objects.EP;
using PX.Objects.GL;
using PX.Objects.GL.FinPeriods;
using PX.Objects.GL.FinPeriods.TableDefinition;
using PX.Objects.SO;
using PX.Reports.Data;
using PX.SM;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PX.Reports.Controls;
using PX.Reports;

namespace test
{
public class SOInvoiceEntryExt : PXGraphExtension<SOInvoiceEntry>
{
InjectDependency]
protected IReportLoaderService ReportLoader { get; private set; }
InjectDependency]
protected IReportDataBinder ReportDataBinder { get; private set; }
#region Event Handlers
public PXAction<PX.Objects.AR.ARInvoice> CreatePDF;
PXButton(CommitChanges = true)]
PXUIField(DisplayName = "Create PDF")]
protected void createPDF()
{
PXLongOperation.StartOperation(Base, delegate ()
{
//Report Paramenters
Dictionary<String, String> parameters = new Dictionary<String, String>();
parametersm"ARInvoice.DocType"] = Base.Document.Current.DocType;
parametersm"ARInvoice.RefNbr"] = Base.Document.Current.RefNbr;
//Report Processing
Report _report = ReportLoader.LoadReport("AR641000", null);
ReportLoader.InitDefaultReportParameters(_report, parameters);
// ReportNode reportNode = ReportProcessor.ProcessReport(_report);

//var reportNode = .ProcessReportDataBinding(_report);

var reportNode = ReportDataBinder.ProcessReportDataBinding(_report);
//Generation PDF
//byte/] data = PX.Reports.Mail.Message.GenerateReport(reportNode, ReportProcessor.FilterPdf).First();
var data = PX.Reports.Mail.Message.GenerateReport(reportNode, RenderType.FilterPdf).First();
//FileInfo file = new FileInfo("report1.pdf", null, data);
////Saving report

string fileName = $"{Base.CurrentDocument.Current.RefNbr.Trim()}-{DateTime.Now.ToString("yyyyMMddHHmmss")}.pdf";
PX.SM.FileInfo file = new PX.SM.FileInfo(fileName, null, data);
UploadFileMaintenance graph = new UploadFileMaintenance();
graph.SaveFile(file);


if (file != null && file.UID != null && file.UID.Value != null)
{
PXNoteAttribute.SetFileNotes(Base.Document.Cache, Base.Document.Current, file.UID.Value);
}



var fileId = file.UID.GetValueOrDefault();

PXNoteAttribute.AttachFile(Base.Document.Cache, Base.Document.Current, file);
//Downloading of the report
// throw new PXRedirectToFileException(file, true);

Base.Save.Press();

});
}
#endregion


public delegate IEnumerable ReleaseDelegate(PXAdapter adapter);
PXOverride]
public IEnumerable Release(PXAdapter adapter, ReleaseDelegate baseMethod)
{
CreatePDF.Press();
PXLongOperation.WaitCompletion(Base.UID);
IEnumerable result = baseMethod(adapter);





return adapter.Get();


}
}
}

 


@Naveen Boga Thank you for the reply. I tried your code, however it is only working for a single invoice. When I release a single invoice from Invoices and Memos screen it worked fine. But when I release multiple invoices from Release AR Documents screen this did not worked for any of the invoices.


Did you debug and verified? Why it is not working? 

I have implemented this at screen level, as you wanted to run all th invoice you might need tweak the code get it worked. Let me know after you debug and what is the problem that you are getting.

 


@Naveen Boga I tried a different approach since Release method is not triggering when we process invoices through Release AR Documents screen. Since I can not update my question according to that, I Ask another question in the community as below for AP Invoices

 


@charithalakshan49  Understood. However, please note that the logic mentioned earlier is functioning correctly. Since you intend to implement it for multiple records in the AP Document Release screen, you may have to modify the code to accommodate bulk records.


Reply