Skip to main content
Answer

Easiest way to set ARInvoice custom field value upon creation from multiple source modules

  • March 29, 2023
  • 9 replies
  • 514 views

darylbowman
Captain II
Forum|alt.badge.img+15

I am trying to set a custom field during the creation of an ARInvoice from the Sales Order module and the Service Management module. Invoices are created in very different ways in both of these, and I’ve been messing with overriding / extending the methods that perform this process, but it’s not going that well and I’m feeling like I have to be missing something easy.

I thought of doing it in an event on the ARInvoiceEntry page, but I don’t think that really accomplishes the need. I think I could use inserted events on several entry screens, but that doesn’t seem like a shortcut either.

Does anyone have an idea of a better way?

Best answer by darylbowman

After spending much more time on this than I was hoping, here’s my end result:

  1. Override / extend ‘PrepareInvoice’ on SOOrderEntry, adding event handlers on the SOInvoiceEntry graph for ARTran RowInserted and ARInvoice RowPersisting. This allows me to handle events that originate from the SOOrderEntry graph that actually take place in the SOInvoiceEntry graph (code block 1)
  2. I can get the information I need from the inserted (but not yet persisted) ARTran, which I can then set in the RowInserting event of ARInvoice

This all was required because I needed to set a value of an ARInvoice originating from an SOOrder but that had not yet been saved, and therefore couldn’t be found.

public delegate IEnumerable PrepareInvoiceDelegate(PXAdapter adapter);

[PXOverride]
public IEnumerable PrepareInvoice(PXAdapter adapter, PrepareInvoiceDelegate baseMethod)
{
// Adds handlers for SOInvoiceEntry events which orginate from SOOrderEntry
PXGraph.InstanceCreated.AddHandler<SOInvoiceEntry>((graph) =>
{
graph.RowPersisting.AddHandler<ARInvoice>((cache, e) =>
{
var invoice = e.Row as ARInvoice;
if (invoice is null) return;

string invoiceStyle = InvoiceStyle;
cache.SetValue<DSAssignInvoiceStyle_SOOrderType_Ext.usrDSInvoiceStyle>(invoice, invoiceStyle);
cache.Update(invoice);
});

graph.RowInserted.AddHandler<ARTran>((cache, e) =>
{
var tran = e.Row as ARTran;
if (tran is null) return;

var invoice = graph.Caches[typeof(ARInvoice)].Current as ARInvoice;
string invoiceStyle = GetInvoiceStyle(tran.SOOrderType);
InvoiceStyle = invoiceStyle;
});
});

return baseMethod(adapter);
}

 

9 replies

aaghaei
Captain II
Forum|alt.badge.img+10
  • Captain II
  • March 29, 2023

@darylbowman 

I am not familiar with Service Mgmt, what DocType does it generate for ARInvoice?


darylbowman
Captain II
Forum|alt.badge.img+15
  • Author
  • March 29, 2023

'INV' but the code is poorly written and it usually needs a .Trim()


aaghaei
Captain II
Forum|alt.badge.img+10
  • Captain II
  • March 29, 2023

Do you (I mean Acumatica) have any differentiator in the ARInvoice which is different between Service and SO? For Example, is the InvoiceNbr of both SO and FS following the same numbering sequence or different? If we find a differentiator, we can make it work much easier.


darylbowman
Captain II
Forum|alt.badge.img+15
  • Author
  • March 29, 2023

Ah, I see where you're coming from. No, they are the same. And the field value is dependent upon another custom value set for the Order Type for SOs and Service Order Type for Service Orders. So it needs to be connected back to the source document.


aaghaei
Captain II
Forum|alt.badge.img+10
  • Captain II
  • March 30, 2023

In this case, your best bet is the SOOrder and Service Order RowPersisted Event (or Persist method). Let the platform do its work and create the Invoice. Then in your Current SO or FS document find the Ref to AR Invoice and update the AR Invoice. If you just to update some fields in ARInvoice from originating docs, you do not need to override the ARInvoice creating methods. 


darylbowman
Captain II
Forum|alt.badge.img+15
  • Author
  • March 30, 2023

This is a great idea, but in Events.RowPersisted<SOOrder>, no SOInvoice exists, which is what I need to find the ARInvoice.

I was finding the same thing extending the PrepareInvoice method.


aaghaei
Captain II
Forum|alt.badge.img+10
  • Captain II
  • March 30, 2023

What I read from your original post, your actions create the invoice. This means before finally your existing SO or FS documents are saved the invoices are created and the reference is returned to source document and you have the required references.

what is the Action name you want to customize on SO that I can have look with a sample custom field myself. What version you are on?


darylbowman
Captain II
Forum|alt.badge.img+15
  • Author
  • March 30, 2023

I am trying to set a custom field during the creation of an ARInvoice from the Sales Order module and the Service Management module.

 

My actions are not creating the Invoices. The Invoices are created during the standard processing. I simply need to set a custom field after the Invoice has been created, but using information from the source document.


darylbowman
Captain II
Forum|alt.badge.img+15
  • Author
  • Answer
  • March 31, 2023

After spending much more time on this than I was hoping, here’s my end result:

  1. Override / extend ‘PrepareInvoice’ on SOOrderEntry, adding event handlers on the SOInvoiceEntry graph for ARTran RowInserted and ARInvoice RowPersisting. This allows me to handle events that originate from the SOOrderEntry graph that actually take place in the SOInvoiceEntry graph (code block 1)
  2. I can get the information I need from the inserted (but not yet persisted) ARTran, which I can then set in the RowInserting event of ARInvoice

This all was required because I needed to set a value of an ARInvoice originating from an SOOrder but that had not yet been saved, and therefore couldn’t be found.

public delegate IEnumerable PrepareInvoiceDelegate(PXAdapter adapter);

[PXOverride]
public IEnumerable PrepareInvoice(PXAdapter adapter, PrepareInvoiceDelegate baseMethod)
{
// Adds handlers for SOInvoiceEntry events which orginate from SOOrderEntry
PXGraph.InstanceCreated.AddHandler<SOInvoiceEntry>((graph) =>
{
graph.RowPersisting.AddHandler<ARInvoice>((cache, e) =>
{
var invoice = e.Row as ARInvoice;
if (invoice is null) return;

string invoiceStyle = InvoiceStyle;
cache.SetValue<DSAssignInvoiceStyle_SOOrderType_Ext.usrDSInvoiceStyle>(invoice, invoiceStyle);
cache.Update(invoice);
});

graph.RowInserted.AddHandler<ARTran>((cache, e) =>
{
var tran = e.Row as ARTran;
if (tran is null) return;

var invoice = graph.Caches[typeof(ARInvoice)].Current as ARInvoice;
string invoiceStyle = GetInvoiceStyle(tran.SOOrderType);
InvoiceStyle = invoiceStyle;
});
});

return baseMethod(adapter);
}