Solved

Custom Processing Form - Not Showing Processing DIalog?

  • 12 January 2022
  • 5 replies
  • 322 views

Userlevel 1

Hello,

I have created a custom processing form, based largely on the info from T240. The Graph makes use of a` PXFilteredProcessing` data view. The grid in the view is dynamically populated based on user selection. Both the loading/filtering of records and processing of checked records seems to work as expected; however, for some reason the Processing Dialog is not showing. When I initiate processing by clicking the “Calcuate” button (the caption I set for my “Process” button), I merely get the little gray loading spinner (the one that appears anytime you save records, navigate, etc. in the system) NOT the actual processing dialog.

I have compared my code against Acumatica’s standard processing forms and see nothing that could explain this behavior. Any guidance would be appreciated.

 

My Graph code (some code omitted for brevity):


public class MHPRProcessBenefits : PXGraph<MHPRProcessBenefits>
{
public PXCancel<ProcessBenefitFilter> Cancel;
public PXFilter<ProcessBenefitFilter> Filter;
public PXFilteredProcessing<PREmployee, ProcessBenefitFilter> ActiveEmps;
public override bool IsDirty => false;


protected IEnumerable<PREmployee> activeEmps()
{
var filter = Filter.Current;

switch (filter?.CalcType)
{
case ACA_INIT:
return SelectFrom<PREmployee>
.Where<PREmployee.vStatus.IsEqual<VendorStatus.active>.And<PREmployeeExtension.usrInitMeasureCalcd.IsEqual<False>>>.View.Select(this).FirstTableItems;
case ACA_STANDARD:
case BENEFIT:
return SelectFrom<PREmployee>
.Where<PREmployee.vStatus.IsEqual<VendorStatus.active>>.View.Select(this).FirstTableItems;
case RETIREMENT:
return SelectFrom<PREmployee>
.Where<PREmployee.vStatus.IsEqual<VendorStatus.active>.And<BAccountRetirmentExtension.usrHoursReqMet.IsEqual<False>>>.View.Select(this).FirstTableItems;
default:
return new List<PREmployee>();

}

}

protected virtual void _(Events.RowSelected<ProcessBenefitFilter> e)
{
var row = e.Row;
if (row == null)
{
return;
}

ActiveEmps.SetProcessCaption("Calculate");
ActiveEmps.SetProcessAllCaption("Calculate All");
ActiveEmps.SetProcessDelegate<PREmployeePayrollSettingsMaint>(
delegate (PREmployeePayrollSettingsMaint graph, PREmployee emp)
{
graph.Clear();
var graphExt = graph.GetExtension<PREmployeeMaintExtension>();

try
{
switch (Filter.Current.CalcType)
{
case AppConstants.CalcOperation.ACA_INIT:
graphExt.updateInitialACA(emp, true);
break;
case AppConstants.CalcOperation.ACA_STANDARD:
graphExt.updateStandardACA(emp, true);
break;
case AppConstants.CalcOperation.BENEFIT:
graphExt.updateBenefitEligibility(emp, true);
break;
case AppConstants.CalcOperation.RETIREMENT:
graphExt.updateRetirement(emp, true);
break;
}

}
catch (Exception ex)
{
PXProcessing.SetError(ex.Message);
}
});

}

The ASPX is very simple too:

<%@ Page Language="C#"  MasterPageFile="~/MasterPages/FormDetail.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="MH501000.aspx.cs" Inherits="Page_MH501000" Title="Untitled Page" %>

<%@ MasterType VirtualPath="~/MasterPages/FormDetail.master" %>

<asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%"
TypeName="PRImport.MHPRProcessBenefits"
PrimaryView="Filter"
>
<CallbackCommands>
</CallbackCommands>
</px:PXDataSource>
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="phF" runat="server">
<px:PXFormView ID="form" runat="server" Style="z-index: 100" Width="100%" DataMember="Filter">
<Template>
<px:PXLayoutRule runat="server" StartRow="True" LabelsWidth="XS" ControlSize="M" />
<px:PXDropDown ID="edAction" runat="server" DataField="CalcType" CommitChanges="True" />
</Template>
</px:PXFormView>
</asp:Content>



<asp:Content ID="Content3" ContentPlaceHolderID="phG" runat="server">
<px:PXGrid ID="grid1" runat="server" Width="100%" AllowPaging="True" AdjustPageSize="Auto" SkinID="Inquire" DataSourceID="ds" ExportNotes="False" NoteIndicator="False" FilesIndicator="False">
<Levels>
<px:PXGridLevel DataMember="ActiveEmps">
<RowTemplate>
<px:PXSelector ID="edRefNbr" runat="server" DataField="RefNbr" AllowEdit="true" ></px:PXSelector>
</RowTemplate>
<Columns>
<px:PXGridColumn DataField="Selected" Width="30px" TextAlign="Center" Type="CheckBox" AllowCheckAll="True" AllowSort="False" AllowMove="False" ></px:PXGridColumn>
<px:PXGridColumn DataField="UsrInitMeasureStart" Width="90" ></px:PXGridColumn>
<px:PXGridColumn DataField="UsrInitMeasureCalcd" Width="60" ></px:PXGridColumn>
<px:PXGridColumn DataField="UsrHoursReqMet" Width="60" ></px:PXGridColumn>
<px:PXGridColumn DataField="UsrCurECPStart" Width="90" ></px:PXGridColumn>
<px:PXGridColumn DataField="AcctName" Width="220" ></px:PXGridColumn>
<px:PXGridColumn DataField="AcctCD" Width="140" ></px:PXGridColumn></Columns>
</px:PXGridLevel>
</Levels>
<AutoSize Container="Window" Enabled="True" MinHeight="300" />
</px:PXGrid>
</asp:Content>

Screenshot of form in UI:

 

icon

Best answer by markusray17 12 January 2022, 20:40

View original

5 replies

Userlevel 6
Badge +5

You want to set the process delegate(as well as the captions) in the graph constructor not in the row selected event but that isn’t what is causing your issue.

I suspect your code is being run synchronously because you are accessing the (this).Filter view. Any reference inside the delegate to the graph instance will cause the code to run synchronously which would prevent the dialog from showing.

You can lexically bind the Filter.Current.CalcType value to a variable in the surrounding closure which should fix the issue.

//Constructor
public MyGraph(){

var filterCalcType = Filter.Current.CalcType;

ActiveEmps.SetProcessCaption("Calculate");
ActiveEmps.SetProcessAllCaption("Calculate All");
ActiveEmps.SetProcessDelegate<PREmployeePayrollSettingsMaint>(
delegate (PREmployeePayrollSettingsMaint graph, PREmployee emp)
{
graph.Clear();
var graphExt = graph.GetExtension<PREmployeeMaintExtension>();

try
{
switch (filterCalcType)
{
case AppConstants.CalcOperation.ACA_INIT:
graphExt.updateInitialACA(emp, true);
break;
case AppConstants.CalcOperation.ACA_STANDARD:
graphExt.updateStandardACA(emp, true);
break;
case AppConstants.CalcOperation.BENEFIT:
graphExt.updateBenefitEligibility(emp, true);
break;
case AppConstants.CalcOperation.RETIREMENT:
graphExt.updateRetirement(emp, true);
break;
}

}
catch (Exception ex)
{
PXProcessing.SetError(ex.Message);
}
});
}

 

Userlevel 1

@markusray17  That little change with the Filter fixed it. Thanks so much! Don’t think I would have ever thought of that.

Userlevel 7
Badge +17

Hi @KellyMarchewa, Yes, as suggested above, we need to have a code at the Constructor level but not the RowSelected event. Here is the code for your reference. 

May help you for your reference.

public class MHPRProcessBenefits : PXGraph<MHPRProcessBenefits>
{
public PXCancel<ProcessBenefitFilter> Cancel;
public PXFilter<ProcessBenefitFilter> Filter;

[PXFilterable]
public PXFilteredProcessing<PREmployee, ProcessBenefitFilter> ActiveEmps;
public override bool IsDirty => false;


protected IEnumerable<PREmployee> activeEmps()
{
var filter = Filter.Current;

switch (filter?.CalcType)
{
case ACA_INIT:
return SelectFrom<PREmployee>
.Where<PREmployee.vStatus.IsEqual<VendorStatus.active>.And<PREmployeeExtension.usrInitMeasureCalcd.IsEqual<False>>>.View.Select(this).FirstTableItems;
case ACA_STANDARD:
case BENEFIT:
return SelectFrom<PREmployee>
.Where<PREmployee.vStatus.IsEqual<VendorStatus.active>>.View.Select(this).FirstTableItems;
case RETIREMENT:
return SelectFrom<PREmployee>
.Where<PREmployee.vStatus.IsEqual<VendorStatus.active>.And<BAccountRetirmentExtension.usrHoursReqMet.IsEqual<False>>>.View.Select(this).FirstTableItems;
default:
return new List<PREmployee>();

}
}

#region Constructor

public MHPRProcessBenefits()
{
ActiveEmps.SetProcessCaption("Calculate");
ActiveEmps.SetProcessAllCaption("Calculate All");
ActiveEmps currentFilter = this.Filter.Current;
ActiveEmps.SetProcessDelegate(
delegate (List<PREmployee> list)
{
ProcessRecords(list, currentFilter);
});
}
#endregion



public static void ProcessRecords(List<PREmployee> list, ProcessBenefitFilter currentFilter)
{
PREmployeePayrollSettingsMaint graph = PXGraph.CreateInstance<PREmployeePayrollSettingsMaint>();

foreach (PREmployee emp in list)
{
graph.Clear();
var graphExt = graph.GetExtension<PREmployeeMaintExtension>();

try
{
switch (Filter.Current.CalcType)
{
case AppConstants.CalcOperation.ACA_INIT:
graphExt.updateInitialACA(emp, true);
break;
case AppConstants.CalcOperation.ACA_STANDARD:
graphExt.updateStandardACA(emp, true);
break;
case AppConstants.CalcOperation.BENEFIT:
graphExt.updateBenefitEligibility(emp, true);
break;
case AppConstants.CalcOperation.RETIREMENT:
graphExt.updateRetirement(emp, true);
break;
}

}
catch (Exception ex)
{
PXProcessing.SetError(ex.Message);
}
}
}
}

 

Userlevel 7
Badge +5

Also I'd like to add to the answer provided by markusray17. there is a visual studio extension called Acuminator that highlights that kind of mistakes.

Userlevel 6
Badge +5

I'm not sure it highlights this specific scenario. I am using the beta visual studio 2022 version of Acuminator but it didn't trigger a warning for this issue when I replicated it.

I think because of the anonymous function it doesn't detect properly. It definitely does detect it when using an instance method on the graph though. 

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