Issue Summary:
The processing logic on my new screen is working but the page doesn't show any feedback to the user (e.g. Timer doesn't show, No Red/Green checkboxes, checkboxes aren't disabled)
Issue Detail:
I'm creating a processing screen that requires separate information from the user to be used by the processing delegate. The business logic works, but the user experience isn't like other processing screens. When you click Process there is nothing shown to the user. Normally the page refreshes the grid by disabling and showing only the selected items being processed, in addition to the long operation timer being added (then replaced by a green check or red x based on whether the process was successful or failed). When I click process all the entire grid's selected column is checked, but again nothing else changes (e.g. no timer, status, nor is the grid disabled). Ultimately both process and process all perform the business logic but the user doesn't see anything to indicate said success/failure.
The screen shows all customer locations because the process is updating some statistics that we are keeping for each location based on orders that exist for each location.
My Graph
public class CalculateLocationStatsProcess : PXGraph<CalculateLocationStatsProcess>
{
public PXCancel<LocationStatsFilter> Cancel;
public PXFilter<LocationStatsFilter> filterLocStat;
public PXFilteredProcessingJoin<Location,
LocationStatsFilter,
InnerJoin<Customer, On<Customer.bAccountID, Equal<Location.bAccountID>>>,
Where<True, Equal<True>>,
OrderBy<Asc<Customer.acctCD, Asc<Location.locationCD>>>> processLocations;
public CalculateLocationStatsProcess()
{
}
public virtual void LocationStatsFilter_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
processLocations.SetProcessDelegate(
delegate (List<Location> list)
{
var newList = new List<Location>();
foreach (Location locLp in list)
{
newList.Add(locLp);
}
CalculateLocationStatsProcess.updateLocationStats(newList, filterLocStat.Current);
}
);
}
public static void updateLocationStats(List<Location> locations, LocationStatsFilter filter)
{
var graph = new PXGraph();
var locStats = new StatsHelper(graph, filter.TargetDate);
bool erred = false;
for (int iLp = 0; iLp < locations.Count; iLp++)
{
Location locationLp = locations[iLp];
PXProcessing<Location>.SetCurrentItem(locationLp);
try
{
locStats.setCommStats(locationLp);
}
catch (Exception ex)
{
erred = true;
PXProcessing<Location>.SetError(iLp, ex.Message);
}
}
locStats.StatCache.Persist(PXDBOperation.Insert);
locStats.StatCache.Persist(PXDBOperation.Update);
if (erred)
{
throw new PXException("Location(s) failed during recalculation process. View individual lines to see their specific error.");
}
}
}
My Page
<%@ Page Language="C#" MasterPageFile="~/MasterPages/FormDetail.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="SO509503.aspx.cs" Inherits="Page_SO509503" Title="Calculate Location Stats" %>
<%@ MasterType VirtualPath="~/MasterPages/FormDetail.master" %>
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" PrimaryView="filterLocStat" TypeName="exampleNS.CalculateLocationStatsProcess">
<CallbackCommands>
</CallbackCommands>
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" runat="Server">
<px:PXFormView ID="formFilter" runat="server" DataMember="filterLocStat" DataSourceID="ds" Style="z-index: 100" Width="100%" >
<Template>
<px:PXLayoutRule runat="server" ID="PXLayoutRule1" ControlSize="M" LabelsWidth="M" StartRow="true" />
<px:PXDateTimeEdit runat="server" ID="edTargetDate" DataField="TargetDate" />
</Template>
</px:PXFormView>
</asp:Content>
<asp:Content ID="cont3" ContentPlaceHolderID="phG" runat="Server">
<px:PXGrid ID="gridLocations" runat="server"
AdjustPageSize="Auto" AllowPaging="True" AllowSearch="true" DataSourceID="ds" FilesIndicator="false"
Height="400px" NoteIndicator="false" SkinID="Inquire" Style="z-index: 100" SyncPosition="true" Width="100%" >
<AutoSize Container="Window" Enabled="True" MinHeight="200" />
<Levels>
<px:PXGridLevel DataMember="processLocations">
<Columns>
<px:PXGridColumn DataField="Selected" Type="CheckBox" AllowCheckAll="true" Width="40px" />
<px:PXGridColumn DataField="Customer__AcctCD" Width="125px" />
<px:PXGridColumn DataField="LocationCD" Width="75px" />
<px:PXGridColumn DataField="Descr" Width="175px" />
</Columns>
</px:PXGridLevel>
</Levels>
</px:PXGrid>
</asp:Content>
My Filter DAC
public class LocationStatsFilter : IBqlTable
{
#region TargetDate
public abstract class targetDate : IBqlField { }
[PXDate()]
[PXUIField(DisplayName = "Target Month and Year")]
public virtual DateTime? TargetDate { get; set; }
#endregion
}
My Location Extension DAC
[PXTable(typeof(Location.locationID), typeof(Location.bAccountID), IsOptional = false)]
public class LocationExt : PXCacheExtension<Location>
{
#region Selected
public abstract class selected : IBqlField { }
[PXBool()]
[PXDefault(false)]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
#endregion
#region DateFirstService
public abstract class dateFirstService : IBqlField { }
[PXDBDate()]
[PXUIField(DisplayName = "Date of First Service")]
public virtual DateTime? DateFirstService { get; set; }
#endregion
}
I modelled my solution after several processing screens that I found, but I've looked at so many I couldn't say which ones I used as examples. I've moved the SetProcessDelegate call between the RowSelected event and the Constructor with no luck. I've attempted making the updateLocationStats function static versus not static (using the existing graph instead) with no success.
UPDATE:
- Calling the updateLocationStats method directly instead of creating a copy of the List didn't change the result.
- Adding PXFilterable to the PXFilteredProcessingJoin didn't change the result
- Removing the calls to locStats (creation, setCommStats(locationLp), Persist) didn't change the result
- Added missing Location DAC
- Attempted moving Selected from LocationExt DAC to a new LocationAlt : Location DAC with no change in result.
- Added DataType="Boolean" to the selected field in the page. No change in behavior
- Added BatchUpdate="True" to the PXGrid tag. No change in behavior.
- Added PXProcessing.SetProcessed(); after locStats.setCommStats(locationLp); no change in behavior.
Alternate Test
public class LocationAlt : Location
{
#region Selected
public abstract class selected : IBqlField { }
[PXBool()]
[PXDefault(false)]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
#endregion
}
public class CalculateLocationStatsProcess : PXGraph<CalculateLocationStatsProcess>
{
public PXCancel<LocationStatsFilter> Cancel;
public PXFilter<LocationStatsFilter> filterLocStat;
[PXFilterable()]
public PXFilteredProcessingJoin<LocationAlt,
LocationStatsFilter,
InnerJoin<Customer, On<Customer.bAccountID, Equal<LocationAlt.bAccountID>>>,
Where<True, Equal<True>>,
OrderBy<Asc<Customer.acctCD, Asc<LocationAlt.locationCD>>>> processLocations;
public CalculateLocationStatsProcess()
{
}
public virtual void LocationStatsFilter_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
processLocations.SetProcessDelegate(
delegate (List<LocationAlt> list)
{
CalculateLocationStatsProcess.updateLocationStats(list, filterLocStat.Current);
}
);
}
public static void updateLocationStats(List<LocationAlt> locations, LocationStatsFilter filter)
{
var graph = new PXGraph();
var locStats = new CommStatsHelper(graph, filter.TargetDate);
bool erred = false;
for (int iLp = 0; iLp < locations.Count; iLp++)
{
LocationAlt locationLp = locations[iLp];
PXProcessing<LocationAlt>.SetCurrentItem(locationLp);
try
{
locStats.setCommStats(locationLp);
}
catch (Exception ex)
{
erred = true;
PXProcessing<LocationAlt>.SetError(iLp, ex.Message);
}
}
locStats.StatCache.Persist(PXDBOperation.Insert);
locStats.StatCache.Persist(PXDBOperation.Update);
if (erred)
{
throw new PXException("Location(s) failed during recalculation process. View individual lines to see their specific error.");
}
}
}
Note that the alternate test didn't work either.