Solved

Pass RefNbr in PrepareInvoice Action

  • 26 December 2021
  • 10 replies
  • 183 views

Hi Team,

I have enabled manual numbering for Invoices. I would like to pass RefNbr field to “PrepareAction” action so that it can take it while creating an invoice. I have override the method “PrepareInvoice” method but looks like all business logic is inside “this.Base.InvoiceOrder” method. Kindly advise how can I set the RefNbr field in PrepareInvoice method ?

 

icon

Best answer by Naveen Boga 28 December 2021, 07:52

View original

10 replies

Userlevel 7
Badge +17

Hi @Shaify,

Instead of overriding the Prepare Invoice action, you can override the Persist delegate at SOInvoiceEntry Graph level and verify.

I have not tested this, but I hope this definitely will works.

 public class SOInvoiceEntry_Extension : PXGraphExtension<SOInvoiceEntry>
{
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate del)
{
if (Base.Document.Cache.GetStatus((object)Base.Document.Current) == PXEntryStatus.Inserted)
{
Base.Document.Current.RefNbr = "XXXX";
Base.Document.Cache.Update(Base.Document.Current);
}
del();
}
}

 

 

Userlevel 5
Badge +3

@Shaify , @Naveen B , I do not believe you should customize the invoice preparation logic at all here

There is already the invoice nbr field in a sales order which supplies the Ref Nbr field when specified. See the SOInvoiceEntry.InvoiceOrder method:

if (soOrder.InvoiceNbr != null)
                    {
                        newdoc.RefNbr = soOrder.InvoiceNbr;

This field is enabled and required only for orders of IN and CM behavior (not processing shipments). If the intention is to manually provide invoice nbr for sales orders of SO behavior, you can enable this field and make it required by a simple customization like this:

public class SOOrderEntryCommCust147EnableInvoiceInfoUnderManualNumbering : PXGraphExtension<SOOrderEntry>
    {

        public bool isInvoiceInfoEnabled (SOOrder doc)
        {
            return (doc.ARDocType != ARDocType.Undefined && doc.IsUserInvoiceNumbering == true
                && doc.BillSeparately == true);
        }
        public virtual void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected baseM)
        {
            baseM(sender, e);
            SOOrder doc = (SOOrder)e.Row;
            if (doc!=null)
                PXUIFieldAttribute.SetEnabled<SOOrder.invoiceNbr>(sender, doc, isInvoiceInfoEnabled(doc));
        }

        public virtual void SOOrder_RowPersisting(PXCache sender, PXRowPersistingEventArgs e, PXRowPersisting baseM)
        {
            baseM(sender, e);
            SOOrder doc = (SOOrder)e.Row;
            PXDefaultAttribute.SetPersistingCheck<SOOrder.invoiceNbr>(sender, doc, isInvoiceInfoEnabled(doc)? PXPersistingCheck.NullOrBlank : PXPersistingCheck.Nothing);
        }
    }

Notice that  this code enables the (and necessitates filling of) the Invoice Nbr field only when Bill Separately = true (because only this setting ensures that this order cannot be invoiced along with other orders. which would have created ambiguity in invoice numbers)

 

@Shaify , @Naveen B , I do not believe you should customize the invoice preparation logic at all here

There is already the invoice nbr field in a sales order which supplies the Ref Nbr field when specified. See the SOInvoiceEntry.InvoiceOrder method:

if (soOrder.InvoiceNbr != null)
                    {
                        newdoc.RefNbr = soOrder.InvoiceNbr;

This field is enabled and required only for orders of IN and CM behavior (not processing shipments). If the intention is to manually provide invoice nbr for sales orders of SO behavior, you can enable this field and make it required by a simple customization like this:

public class SOOrderEntryCommCust147EnableInvoiceInfoUnderManualNumbering : PXGraphExtension<SOOrderEntry>
    {

        public bool isInvoiceInfoEnabled (SOOrder doc)
        {
            return (doc.ARDocType != ARDocType.Undefined && doc.IsUserInvoiceNumbering == true
                && doc.BillSeparately == true);
        }
        public virtual void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected baseM)
        {
            baseM(sender, e);
            SOOrder doc = (SOOrder)e.Row;
            if (doc!=null)
                PXUIFieldAttribute.SetEnabled<SOOrder.invoiceNbr>(sender, doc, isInvoiceInfoEnabled(doc));
        }

        public virtual void SOOrder_RowPersisting(PXCache sender, PXRowPersistingEventArgs e, PXRowPersisting baseM)
        {
            baseM(sender, e);
            SOOrder doc = (SOOrder)e.Row;
            PXDefaultAttribute.SetPersistingCheck<SOOrder.invoiceNbr>(sender, doc, isInvoiceInfoEnabled(doc)? PXPersistingCheck.NullOrBlank : PXPersistingCheck.Nothing);
        }
    }

Notice that  this code enables the (and necessitates filling of) the Invoice Nbr field only when Bill Separately = true (because only this setting ensures that this order cannot be invoiced along with other orders. which would have created ambiguity in invoice numbers)

 

@mvolshteyn : Thanks for the reply. I tried above code but getting an error below:

 

Hi @Shaify,

Instead of overriding the Prepare Invoice action, you can override the Persist delegate at SOInvoiceEntry Graph level and verify.

I have not tested this, but I hope this definitely will works.

 public class SOInvoiceEntry_Extension : PXGraphExtension<SOInvoiceEntry>
{
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate del)
{
if (Base.Document.Cache.GetStatus((object)Base.Document.Current) == PXEntryStatus.Inserted)
{
Base.Document.Current.RefNbr = "XXXX";
Base.Document.Cache.Update(Base.Document.Current);
}
del();
}
}

 

 

 

@Naveen B : I tried this way but didn’t work.

Userlevel 7
Badge +17

Hi @Shaify  Please understand the functionality that provided by @mvolshteyn 

  • Since you are going with the Manual Numbering for the Invoice Nbr, he is indicating that no need of overriding the “Prepare Invoice” action. You can use the Invoice Nbr field from Sales Order screen.
  • But, the Sales Orders → Financial Settings →  Invoice Nbr  field will be enabled only for the CM and IN type orders.
  • You can have small customization in place to enable the “Invoice Nbr” field for the other order types, and then when you click on the Prepare Invoice action, Invoice document will be created with the provided Invoice Nbr field in the Sales Order screen.
  • You can take the above code just for your reference.

Note: Invoice Nbr field will enabled only when you check the “Bill Separately” checkbox.

Hi @Shaify  Please understand the functionality that provided by @mvolshteyn 

  • Since you are going with the Manual Numbering for the Invoice Nbr, he is indicating that no need of overriding the “Prepare Invoice” action. You can use the Invoice Nbr field from Sales Order screen.
  • But, the Sales Orders → Financial Settings →  Invoice Nbr  field will be enabled only for the CM and IN type orders.
  • You can have small customization in place to enable the “Invoice Nbr” field for the other order types, and then when you click on the Prepare Invoice action, Invoice document will be created with the provided Invoice Nbr field in the Sales Order screen.
  • You can take the above code just for your reference.

Note: Invoice Nbr field will enabled only when you check the “Bill Separately” checkbox.

@Naveen B : Thanks I have understood the @mvolshteyn response.

Userlevel 7
Badge +17

Hi @Shaify  Great :)  After implemented above approach, please let us know if you get any issues.

@Naveen B : I am getting below error after implementing the above approach and also replied on the same.

 

 

Userlevel 7
Badge +17

@Shaify  I have modified a bit and you can use below code and check.

using PX.Data;
using PX.Objects.AR;
using PX.Objects.SO;

namespace Test
{
public class SOOrderEntryCommCust147EnableInvoiceInfoUnderManualNumbering : PXGraphExtension<SOOrderEntry>
{

public virtual void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected baseM)
{
baseM(sender, e);
SOOrder doc = (SOOrder)e.Row;
if (doc != null)
PXUIFieldAttribute.SetEnabled<SOOrder.invoiceNbr>(sender, doc, isInvoiceInfoEnabled(doc));
}

public virtual void SOOrder_RowPersisting(PXCache sender, PXRowPersistingEventArgs e, PXRowPersisting baseM)
{
baseM(sender, e);
SOOrder doc = (SOOrder)e.Row;
PXDefaultAttribute.SetPersistingCheck<SOOrder.invoiceNbr>(sender, doc, isInvoiceInfoEnabled(doc) ? PXPersistingCheck.NullOrBlank : PXPersistingCheck.Nothing);
}


public bool isInvoiceInfoEnabled(SOOrder doc)
{
return (doc.ARDocType != ARDocType.Undefined && Base.soordertype.Current.UserInvoiceNumbering == true
&& doc.BillSeparately == true);
}
}
}

 

Userlevel 5
Badge +3

@Naveen B , thanks for the follow up

@Shaify , sorry for confusion. It turned out that the IsUserInvoiceNumbering field was introduced only in 21R2 version, probably you are working on the earlier version. In this case, you should follow the suggestion of @Naveen B  to replace this DAC field with the Current member of SOOrderType, but only if you do not intend to use the Copy Order function to copy orders to ones with different automation behavior (e.g. QT to SO or SO to CM). When Copy Order function is run, the soordertype.Current might not be synced with the order type of SOOrder by the time of these handlers are run

So, if you intend to use the Copy Order function and run this solution on versions prior to 21R2, you can just mimic the product behavior by adding this field in the SOOrder DaC extension with the following attributes:

 

public abstract class isUserInvoiceNumbering : Data.BQL.BqlBool.Field<isUserInvoiceNumbering> { }
[PXBool]
[PXFormula(typeof(Where<Selector<orderType, SOOrderType.userInvoiceNumbering>, Equal<True>>))]
public virtual bool? IsUserInvoiceNumbering
{
get;
set;
}

 

and accessing this SOOrder extension in the isInvoiceInfoEnabled function.

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