Render Action button - acumatica

I was creating a new Screen with the FormDetail template where I would be having a Filter DAC and list of DAC to display on Grid. I created the page successfully. Then,I wanted to put a button on the top of the button which would pull data from api and refresh grid. So, I wrote the below code to render an action button on page(FormDetail) like this.
But, it is not working.
using System;
using PX.Data;
namespace AcumaticaSquarePOSIntegration
{
public class SquarePOSTransactionInquiry : PXGraph<SquarePOSTransactionInquiry>
{
public PXSave<MasterTable> Save;
public PXCancel<MasterTable> Cancel;
public PXFilter<MasterTable> MasterView;
public PXFilter<DetailsTable> DetailsView;
public PXAction<MasterTable> Calc;
[PXUIField(DisplayName="Calc")]
[PXButton]
protected virtual IEnumerable calc(PXAdapter adapter)
{
return adapter.Get();
}
[Serializable]
public class MasterTable : IBqlTable
{
}
[Serializable]
public class DetailsTable : IBqlTable
{
}
}
}
I even tried add
Is there anything that I am missing here?

You have two PXFilters, change the second to PxSelect and make the PXFilter your first Data view in the list.

try using PXProcessButton instead of PXButton.
Also make sure MasterView is specified in aspx as a PrimaryView.

Related

How to fire FieldSelecting event only in the screen?

I have a number of non persistent fields that get its value via FieldSelecting events. The events do the same queries and calculations so I decided to move them into an attribute that implements IPXFieldSelectingSubscriber interface. This works fine and it minimises duplicate codes. However, the event fires every single time the DAC is accessed. Be that in GIs or called in some other graphs. Is there such a flag to verify if the event is being fired only from a specific screen ?
The easiest way to do that would be to add the validation of which screen is accessing the DAC, you can do that by simply putting an if statement like below into your event handler.
if(graph.Accessinfo.ScreenID == "SO.30.10.00")
{
//execute the logic
}
else
{
//skip
}
An alternative solution would be to have the base field type declared on your DAC and then within a graph extension specific to the page you want the logic on, you would declare a CacheAttached event with the custom attribute.
DAC field :
public sealed class APInvoiceExtension : PXCacheExtension<APInvoice>
{
#region UsrTotal
public abstract class usrTotal : BqlDecimal.Field<usrTotal>
{
}
[PXDBDecimal]
[PXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "Total")]
public decimal? UsrTotal { get; set; }
#endregion
}
Graph Extension :
public class APInvoiceEntryExtension : PXGraphExtension<APInvoiceEntry>
{
[PXMergeAttributes(Method = MergeMethod.Append)]
[CustomCalculationAttribute]
protected virtual void __(Events.CacheAttached<APInvoiceExtension.usrTotal> e)
{
}
}

Create missing data on RowSelected

We have a graph extension that manages the tab we added to a screen. The tab displays data from our own DAC. We do not use a DAC extension, not going to go into the reasons right now.
When a user opens the main screen I want to create a record of our data if it does not exist, with some defaulting business logic.
I added a RowSelected event handler on the main DAC and it fires as I expect it to. When I add the code to create our missing record in the event handler Acuminator gives me error "PX1044 Changes to PXCache cannot be performed in event handlers."
I understand the error that Acuminator is raising, but I'm not sure where else to create our record. I cannot remember a section of the university specifically addressing this scenario.
Can anyone tell me how I would handle this scenario? And if possible, point me at the learning material that covers this scenario for broader information.
Unfortunatly there are only a few OK ways to do this and make Acuminator happy. You will risk data inconsistency.
https://github.com/Acumatica/Acuminator/blob/master/docs/diagnostics/PX1044.md
I would reccomend putting your data insertion code in Row Updated and hope the user updates something
I got a reply from Acumatica support, you can do this in a view select delegate.
Here's some example code, I haven't tested it though:
public class InventoryItemMaintExtension : PXGraphExtension<InventoryItemMaint>
{
public SelectFrom<MyCustomTable>.
Where<MyCustomTable.inventoryID.IsEqual<
InventoryItem.inventoryID.FromCurrent>>.
View AdditionalItemData;
public static bool IsActive() { return true; }
public IEnumerable additionalItemData()
{
var data = AdditionalItemData.SelectSingle();
if (data is null)
{
data = new MyCustomTable();
AdditionalItemData.Insert(data);
}
return AdditionalItemData.Select();
}
}
[PXCacheName("Additional Item Data")]
[Serializable]
public class MyCustomTable : IBqlTable
{
#region CashAccountID
[Inventory]
[PXDefault]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : PX.Data.BQL.BqlInt.Field<inventoryID> { }
#endregion
#region Required
[PXDBBool()]
[PXDefault(false)]
[PXUIField(DisplayName = "Required")]
public virtual bool? Required { get; set; }
public abstract class required : PX.Data.BQL.BqlBool.Field<required> { }
#endregion
}

Problem with custom processing button to generate NoteIDs

Creating a new dummy maintenance screen to enable universal search on item cross references and gotten as far as creating the new DAC and BLC, even adding the Processing buttons to the screen, but when clicking the either processing button nothing happens (currently have it throwing a PXException). Ultimately I need to use the "Process All" (labeled "Create NoteIDs") button to fill in the NoteID field so I can actually work on the universal search part.
This is my graph. The INItemXRef is actually a new custom DAC with a NoteID field attached (no other changes, created directly from the database). Ultimately I need to update the code below to fill in random values to empty NoteIDs, so if there is any advice on the next step that would also be appreciated after solving the immediate problem:
public class INItemXRefGraph : PXGraph<INItemXRefGraph>
{
public PXSelect<INItemXRef> INItemXRef;
public PXSave<INItemXRef> Save;
public PXFilter<INItemXRef> MasterView;
[PXFilterable]
public PXProcessing<INItemXRef, Where<INItemXRef.noteID, IsNull>> INDocumentList;
public INItemXRefGraph()
{
INDocumentList.SetProcessDelegate(ReleaseDoc);
INDocumentList.SetProcessAllCaption("Create NoteIDs");
}
public static void ReleaseDoc(System.Collections.Generic.List<INItemXRef> list)
{
throw new PXException("Hello World");
}
Try this
public class INItemXRefGraph : PXGraph<INItemXRefGraph>
{
public PXSelect<INItemXRef> INItemXRef;
public PXSave<INItemXRef> Save;
public PXFilter<INItemXRef> MasterView;
[PXFilterable]
public PXProcessing<INItemXRef, Where<INItemXRef.noteID, IsNull>> INDocumentList;
public INItemXRefGraph()
{
INDocumentList.SetProcessDelegate(
delegate(System.Collections.Generic.List<INItemXRef> list)
{
System.Collections.Generic.List<INItemXRef> newlist = new System.Collections.Generic.List<INItemXRef>(list.Count);
foreach (INItemXRef doc in list)
{
newlist.Add(doc);
}
ReleaseDoc(newlist);
}
);
INDocumentList.SetProcessAllCaption("Create NoteIDs");
}
public static void ReleaseDoc(System.Collections.Generic.List<INItemXRef> list)
{
throw new PXException("Hello World");
}

Button not showing in the UI

I'm extending the AccountByPeriodEnq logic, I just want to add a button on top of my screen to modify the selected GL records but it just doesnt want to show up and I can't figure out why.
Here's my code :
namespace PX.Objects.GL
{
class AccountByPeriodEnqExtensions : PXGraphExtension<AccountByPeriodEnq>
{
#region Actions
public PXAction<AccountByPeriodFilter> Letter;
[PXUIField(Visible = true, DisplayName = "Lettrer")]
[PXButton(CommitChanges = true)]
protected virtual IEnumerable letter(PXAdapter adapter)
{
IReadOnlyCollection<GLTranR> selectedTrans = GetSelectedTrans();
if (selectedTrans.Any())
{
PXLongOperation.StartOperation(this, delegate ()
{
foreach(GLTranR line in selectedTrans)
{
// UpdateSomeFieldsAndPersists
}
});
}
else
{
throw new PXException("Error");
}
return Base.Filter.Select();
}
#endregion
#region Utility
private IReadOnlyCollection<GLTranR> GetSelectedTrans()
{
return Base.GLTranEnq.Cache.Updated
.Cast<GLTranR>()
.Where(tran => tran.Selected == true)
.ToArray();
}
#endregion
}
}
Is there anything I'm missing here ?
Regards,
Edit:
To clarify i'm trying to customize the GL404000, Account Details. And using the inspector I saw the Business logic is in the AccountByPeriodEnq Graph
Using Acumatica Inspect Element feature notice that the 'Account by Period' screen (GL402000) is not using the 'AccountByPeriodEnq' graph.
It is using the 'AccountHistoryByYearEnq' graph instead so that's the graph you want to target:
You also need to declare Actions on the primary DAC of that Graph.
The one for 'AccountHistoryByYearEnq' is a little bit harder to find than usual.
You can use Acumatica Source Code page and search for 'PXPrimaryGraph(typeof(AccountHistoryByYearEnq)':
In this case it is AccountByYearFilter DAC that you should use:
[System.SerializableAttribute()]
[PXCacheName(Messages.Account)]
[PXPrimaryGraph(typeof(AccountHistoryByYearEnq), Filter = typeof(AccountByYearFilter))]
public partial class Account : PX.Data.IBqlTable, PX.SM.IIncludable
{
[…]
}
I think this is a special case for Filter, when there's no filter Account would have been the DAC to use for the Actions.
Now that you have identified the Primary Graph of the Screen (AccountHistoryByYearEnq) and the Primary DAC of the Graph (AccountByYearFilter) it should work as expected:
public class AccountByPeriodEnq_Extension : PXGraphExtension<AccountHistoryByYearEnq>
{
public PXAction<AccountByYearFilter> letter;
[PXUIField(DisplayName = "Letter")]
[PXButton]
protected virtual IEnumerable Letter(PXAdapter adapter)
{
return adapter.Get();
}
}
UI:
EDIT:
For Account detail page (GL404000), use the same code with different DAC and Graph:
using PX.Data;
using System.Collections;
namespace PX.Objects.GL
{
public class AccountByPeriodEnq_Extension : PXGraphExtension<AccountByPeriodEnq>
{
#region Actions
public PXAction<AccountByPeriodFilter> letter;
[PXUIField(DisplayName = "Letter")]
[PXButton]
protected virtual IEnumerable Letter(PXAdapter adapter)
{
return adapter.Get();
}
#endregion
}
}
With a base Acumatica install that's all that is needed for the Action to appear:
Note that you can specify explicit state and view rights for the button control, though I don't think your issue is related to access rights if you're working in a developer instance:
[PXUIField(DisplayName = "Letter",
MapEnableRights = PXCacheRights.Select,
MapViewRights = PXCacheRights.Select)]
I finally found my problem, I missed the public member for my class.
namespace PX.Objects.GL
{
public class AccountByPeriodEnqExtensions : PXGraphExtension<AccountByPeriodEnq>
{
#region Actions
public PXAction<AccountByPeriodFilter> Letter;
Thanks for your answer HB, i'll reuse it.

Adding a Customized Button to a Processing Page [Acumatica]

I am trying to customise an Acumatica Processing Page by adding my own processing button. I have tried the usual methods of extending the processing page but unfortunately the button is not displayed on the page.
public class APPrintChecks_Extension : PXGraphExtension<APPrintChecks>
{
public PXAction<APPayment> Test;
[PXProcessButton]
[PXUIField(DisplayName = "Button Test")]
protected virtual IEnumerable test(PXAdapter adapter)
{
return adapter.Get();
}
}
I do not want to override the existing functionality provided by the processing button and as such would like to add my own.
Thanks.
The primary view of the Process Payments / Print Checks page is Filter which is of type PrintChecksFilter. So you need to have your PXAction on that Type. Try to replace
public PXAction<APPayment> Test;
with
public PXAction<PrintChecksFilter> Test;

Resources