How to avoid navigation away from created item after calling PressSave or Persist action

Hello everybody,

today I want to tell you a story, that swallowed quite big amount of time of whole team.

Recently we've got seemingly easy to fulfil requirement: 

  1. Add button to the grid
  2. Inside of the button fullfil 
    1. Persist
    2. Call to db with modifications
    3. Persist one more time
  3. Leave the page opened on created item in UI

Initially our code looked like this:

public PXAction<SOOrder> SomeAction;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Some Action", Visible = true)]
protected virtual IEnumerable someAction(PXAdapter adapter)
{
    Base.Actions.PressSave();
    //API call
    Base.Actions.PressSave();
    return adapter.Get();
}

I could say that everything worked perfectly except one tiny detail: after clicking of the button page was navigated away to creation of new Sales order. After plenty of research inside of Acumatica source code we have found this option:

public PXAction<SOOrder> SomeAction;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Some Action", Visible = true)]
protected virtual IEnumerable someAction(PXAdapter adapter)
{
    Base.Actions.PressSave();
    List<SOOrderresult = new List<SOOrder>();
    //API Call
    result.Add(Base.CurrentDocument.Current);
    return result;
}

Another way of dealing with this bug is this:

public PXAction<SOOrder> SomeAction1;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Some Action", Visible = true)]
protected virtual IEnumerable btnCreatingNew(PXAdapter adapter)
{
    Base.Actions.PressSave();
    //some other code
    adapter.Searches[adapter.Searches.Length - 1] = Base.CurrentDocument.Current.RefNbr;
    return adapter.Get();
}

Summary

Reason of such behavior is fact that Acumatica uses value returned from action in order to know which order to open. Then happens this:

  1. on the first line of the code your adapter has information that Acumatica should go to <New> sales order
  2. Base.Actions.PressSave() generates sales order and persists it to Db, but doesn't notify adapter about this fact
  3. When adapter.Get is executed, Acumatica reads from it order which should be opened, finds there <New> and navigates away from created SO

In order to deal with you can choose option 1, or option 2. Option 1 I've discovered in Acumatica source code, and option 2 is mentioned at stackoverflow by Ruslan

 

 

 

How to rename buttons Process and Process All at processing screens of Acumatica

Hello everybody,

today I want to leave short notice on quesiton how to rename buttons or if to be more specific change title of buttons at Processing screens. By default those buttons have captions Process and Process All. The simplest way to rename them is to use constructor of processing graph. In constructor you can make something like this:

public YourGraph()
{
        Actions["Process"].SetCaption("Email");
        Actions["ProcessAll"].SetCaption("Email All");
}

With such simple trick, you can assign any caption you wish to your buttons

How to handle time consuming operations in Acumatica from code

Hello everybody,

today I want to make a short note on how to handle cases if you need to execute some kind of long operation in Acumatica. Once I had a task, create code that executes some kind of web requests that take some amount of time. When I used simple button, that approach died because of time out. In order to handle it I've decided to use PXLongOperation.StartOperation.

Below goes full sample of code:

public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
    public PXAction<SOOrder> Test;
 
    [PXProcessButton(Tooltip = "Test")]
    [PXUIField(DisplayName = "Test")]
    public virtual IEnumerable test(PXAdapter adapter)
    {
        PXLongOperation.StartOperation(thisdelegate
        {
            SomeLongRunningMethod();
        });
        return adapter.Get();
    }
 
    private static void SomeLongRunningMethod()
    {
        // here is some code
    }
}

with such approach you can get better look and feel for your end customers as well as avoid crashing of your app

Some notes on Buttons creation in Acumatica

Hello everybody,

today I want to write few words about buttons usage in Acumatica.

So, first of all, if you just need to add button at your form, you can use following syntax:

 

public PXAction<PrimaryDACClass> SomeAction;

[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Some Action")]
protected virtual void someAction()
{
      ...
}

Following syntax will create a button for you in the top buttons panel of Acumatica.

Take note of CommitChanges=true attribute. In case if you need just some activity without persistance to database, then you can set it to false. But if you want button to save some changes to database then set it always to true.

There is one more way of declaring buttons:

[PXButton]
[PXUIField(DisplayName = "Some action")]
protected virtual IEnumerable someAction(PXAdapter adapter)
{
...
return adapter.Get();
}

take note that in comparison with previous time method of button returns ienumerable, and also in the end has return adapter.Get();

This type of calling should be used if button is called from processing page or if button initializes background operation.

Two kinds of buttons in Acumatica

Hello everybody,

today I want to write a few words about two types of buttons in Acumatica.

  • usual form of declaration
  • unusual form of declaration

What is difference from code prospecitve?

In the begining they are equal:

public PXAction<Shipment> CancelShipment; 

Even very similar with attributes:

1. 

         [PXButton(CommitChanges = true)]

         [PXUIField(DisplayName = "Cancel Shipment")] 

2. 

        [PXButton]

        [PXUIField(DisplayName = "Release")] 

But different with declaration:

  • protected virtual void cancelShipment() 
  • protected virtual IEnumerable release(PXAdapter adapter) 

and different with last statement. Those with PXAdaapter should return adapter.get(); Like  this:

 

[PXButton]

[PXUIField(DisplayName = "Release")]

protected virtual IEnumerable release(PXAdapter adapter)

{    

             ...    

             return adapter.Get();

 

And one more. Unusual should be used when click on button initates background operation or is called from processing pages

Enable disable button of grid or PXToolBarButton, which depends from value of column in Acumatica

Hello everybody.

My next notice is about following case. 

Suppose you have from PR301000, which has grid with id "grid" with button calculate. Also grid has column, which is bounded to column caculated, and you need the following:

If in selected row field "Calculated" is true, then disable button Calculate. If in selected row field "Calculated" is unchecked, then enable button calculate. 

In order to implement this following should be implemented:

1. In grid at page pr301000:

        <ActionBar ActionsText="True">

   <CustomItems>

                <px:PXToolBarButton Text="Calculate" DependOnGrid="grid" StateColumn="Calculated">

   <AutoCallBack Command="Calculate" Target="ds" >

                    </AutoCallBack>

   </px:PXToolBarButton>

            </CustomItems>

</ActionBar>

2. In ds section write the following:

<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" PrimaryView="PayRolls" SuspendUnloading="False" TypeName="DS.PayRollManager">

        <CallbackCommands>

            <px:PXDSCallbackCommand Name="Calculate" Visible="False" DependOnGrid="grid">

            </px:PXDSCallbackCommand>

        </CallbackCommands>

</px:PXDataSource>

3. Declaration in dac class should be the following:

#region Calculated

public abstract class calculated : PX.Data.IBqlField

{

}

protected bool? _Calculated;

[PXDBBool()]

[PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]

[PXUIField(DisplayName = "Calculated")]

public virtual bool? Calculated

{

get

{

return this._Calculated;

}

set

{

this._Calculated = value;

}

}

#endregion

after I implemented those changes button calculated taken into account field Calculated

Add button to grid in Acumatica

Hello everybody,

today I want briefly share how to add button to Grid in Acumatica. Actually button without any dialogs. Just button with posibility to run C# code.

Lets say you have grid, and want name for button Calculate. 

Then in graph you should write something like this:

public PXAction<PRPayroll> Calculate;
[PXButton]
[PXUIField(DisplayName = "Calculate")]
public virtual IEnumerable calculate(PXAdapter adapter)
{
   return adapter.Get();
}

And in grid something like this:

 <ActionBar ActionsText="True">
    <CustomItems>
        <px:PXToolBarButton>
        <AutoCallBack Command="Calculate" Target="ds" >
             </AutoCallBack>
       </px:PXToolBarButton>
     </CustomItems>
 </ActionBar>
</px:PXGrid>

And you'll get in your grid nice button Calculate. Enjoy