Skip to main content
Solved

Attach files to file section from process screen does not work


Forum|alt.badge.img+1

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);
}

 

Best answer by Naveen Boga

@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.

View original
Did this topic help you find an answer to your question?

12 replies

Forum|alt.badge.img+9
  • Semi-Pro III
  • 229 replies
  • May 23, 2023

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>();
        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);

        // Generate 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);
        file.UID = noteID;

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

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

        // Update the note ID of the invoice to the unique note ID
        invoice.NoteID = noteID;
        Base.Caches[typeof(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


Forum|alt.badge.img+1

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.Caches[typeof(ARInvoice)], invoice, file.UID);

 


Forum|alt.badge.img+9
  • Semi-Pro III
  • 229 replies
  • June 1, 2023

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.Caches[typeof(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


Forum|alt.badge.img+1

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


Forum|alt.badge.img+1

@Naveen Boga  Can you help me on this?


davidnavasardyan
Jr Varsity I
Forum|alt.badge.img+2

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>();
    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);

    // 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.Caches[typeof(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.


Forum|alt.badge.img+1

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


Naveen Boga
Captain II
Forum|alt.badge.img+19
  • Captain II
  • 3412 replies
  • June 28, 2023
charithalakshan49 wrote:

@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>();
                parameters["ARInvoice.DocType"] = Base.Document.Current.DocType;
                parameters["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();


        }
    }
}

 


Forum|alt.badge.img+1

@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.


Naveen Boga
Captain II
Forum|alt.badge.img+19
  • Captain II
  • 3412 replies
  • June 29, 2023

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.

 


Forum|alt.badge.img+1

@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

 


Naveen Boga
Captain II
Forum|alt.badge.img+19
  • Captain II
  • 3412 replies
  • Answer
  • July 10, 2023

@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


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings