Skip to main content
Question

Approval Maps GI

  • July 19, 2026
  • 1 reply
  • 71 views

Forum|alt.badge.img

Hi, I created a GI to show approval maps (XML attached). How do I set the sorting of Steps and Rules in ascending? Note that sorting of Rule description to ‘ascending’ won’t work. Also, how do I show the Entity and Field name from schema instead of DAC name?

Approval Maps Steps and Rules
Showing DAC name instead of Schema
Schema name

 

1 reply

arpine08
Jr Varsity I
Forum|alt.badge.img+1
  • Jr Varsity I
  • July 26, 2026


Hi ​@MarkD,

I suggest the following approach for sorting Approval Map steps/rules and displaying the Entity and Field display names in a Generic Inquiry.

Sorting - Steps:
1. Data Sources

Add PX.Objects.EP.EPRule as an additional data source using the alias ParentEPRule.

2. Relations

Create a LEFT JOIN using the following relation:

EPRule.StepID = ParentEPRule.RuleID

Note: As shown in the SQL  → table: EPRule screenshot, Approval Map Steps and Rules are stored differently. For a Step, StepID is NULL. For a Rule, StepID contains the parent Step's RuleID.

3. Sort Order

Add the following calculated expression and sort it in ascending order:

= Right('0000' + CStr(IsNull([ParentEPRule.Sequence],[EPRule.Sequence])), 4)
+ Right('0000' + CStr(IsNull([ParentEPRule.Sequence],0)), 4)
+ Right('0000' + CStr([EPRule.Sequence]), 4)

The calculated expression combines the parent and current sequences to keep each Step together with its related Rules in the correct hierarchy.

4. Results Grid

Add the same calculated expression to the Results Grid with the caption Sort Key.

This makes it easier to review the generated sorting values directly in the Generic Inquiry. After verification, the column can be hidden or made inactive.

Result:

 

The updated Generic Inquiry XML file is attached.

 

Display Names - Steps:

In the standard implementation, the Entity and Field display names are retrieved by the EPRuleCondition_Entity_FieldSelecting and EPRuleCondition_FieldName_FieldSelecting event handlers in the EPApprovalAndAssignmentMapBase reusable graph. These event handlers are not executed in a Generic Inquiry.

To provide the same display names in a Generic Inquiry, create two unbound DAC fields and populate them using a custom attribute based on the logic from these event handlers, specifically the EMailSourceHelper.TemplateEntity method used to retrieve the Entity and Field display names.

C#: 

using System;
using System.Linq;
using PX.Data;
using PX.Objects.EP;
using PX.SM;

// 1. DAC Extension
public sealed class EPRuleConditionExt : PXCacheExtension<EPRuleCondition>
{
public static bool IsActive() => true;

[PXString(255, IsUnicode = true)]
[PXUIField(DisplayName = "Entity")]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
[ApprovalDisplayName(ApprovalDisplayTarget.Entity)]
public string UsrEntityDisplayName { get; set; }
public abstract class usrEntityDisplayName : PX.Data.BQL.BqlString.Field<usrEntityDisplayName> { }

[PXString(255, IsUnicode = true)]
[PXUIField(DisplayName = "Field Name")]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
[ApprovalDisplayName(ApprovalDisplayTarget.Field)]
public string UsrFieldDisplayName { get; set; }
public abstract class usrFieldDisplayName : PX.Data.BQL.BqlString.Field<usrFieldDisplayName> { }
}

// 2. Enum
public enum ApprovalDisplayTarget
{
Entity,
Field
}

// 3. Attribute
public class ApprovalDisplayNameAttribute : PXEventSubscriberAttribute, IPXFieldSelectingSubscriber
{
private readonly ApprovalDisplayTarget _target;

public ApprovalDisplayNameAttribute(ApprovalDisplayTarget target)
{
_target = target;
}

public void FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
{
var row = e.Row as EPRuleCondition;
if (row == null)
return;

string originalValue = _target == ApprovalDisplayTarget.Entity ? row.Entity : row.FieldName;

e.ReturnValue = originalValue;

var graph = sender.Graph as PXGenericInqGrph;

if (graph == null)
return;

try
{
EPRule rule = PXSelect<EPRule, Where<EPRule.ruleID, Equal<Required<EPRule.ruleID>>>>.Select(graph, row.RuleID);
if (rule?.AssignmentMapID == null) return;

EPAssignmentMap map = PXSelect<EPAssignmentMap, Where<EPAssignmentMap.assignmentMapID, Equal<Required<EPAssignmentMap.assignmentMapID>>>>.Select(graph, rule.AssignmentMapID);
if (map == null) return;

CacheEntityItem entityItem = EMailSourceHelper.TemplateEntity(graph, null, map.EntityType, map.GraphType, false)
.Cast<CacheEntityItem>()
.FirstOrDefault(x => string.Equals(x.SubKey, row.Entity, StringComparison.OrdinalIgnoreCase));

if (entityItem == null)
{
e.ReturnValue = originalValue;
return;
}

if (_target == ApprovalDisplayTarget.Entity)
{
e.ReturnValue = entityItem.Name ?? originalValue;
return;
}
if (_target == ApprovalDisplayTarget.Field)
{
CacheEntityItem fieldItem = EMailSourceHelper.TemplateEntity(graph, entityItem.Key, map.EntityType, map.GraphType, false)
.Cast<CacheEntityItem>()
.FirstOrDefault(x => string.Equals(x.SubKey, row.FieldName, StringComparison.OrdinalIgnoreCase));

e.ReturnValue = fieldItem?.Name ?? originalValue;
return;
}
}
catch (Exception exception)
{
PXTrace.WriteError(exception);
e.ReturnValue = originalValue;
}
}
}

Result Grid: Add two unbound DAC fields UsrEntityDisplayName, UsrFieldDisplayName 

Result:

The attached ApprovalMapsGI.zip customization package also includes the C# code and the updated Generic Inquiry XML file.