Skip to main content
Answer

Filtering a View that has custom fields using the column filters on the grid

  • July 20, 2025
  • 2 replies
  • 67 views

Joe Schmucker
Captain II
Forum|alt.badge.img+3

I have added two unbound custom fields to the List Members grid of the Marketing Lists screen.

These fields are coming from two Attributes on the Contact.

They display correctly which is a good start.  However, if I try to sort by Department for instance, it sorts the current list of items in the grid, not all records in the grid.

If I try to filter the Department column by “SALES”, it shows one record for SALES.  I believe it is grabbing just one record from what is being displayed in the grid, not all records in the grid.

I suspect this might be due to the fact that I have unbound fields added to the grid’s DAC.

It is not an option to add these two fields to the table.  This would not be a viable solution.

I overrode a method to get these values from the contact attributes for each record.

Here is my method to get those unbound fields.

[PXProtectedAccess]
public virtual IEnumerable listMembers()
{
if (Base.MailLists.Current is null)
yield break;

PXCache myCache = Base.Caches<Contact>();

CSAnswers answer;
CSAttributeDetail detail;

foreach (var item in Base.MemberRepository.GetMembers(
Base.MailLists.Current,
new Options { WithViewContext = true }))
{
var member = item.GetItem<CRMarketingListMember>();

if (Base.ListMembers.Cache.Locate(member) == null)
{
Base.ListMembers.Cache.Hold(member);
}

Contact contact = SelectFrom<Contact>.Where<Contact.contactID.IsEqual<@P.AsInt>>.View.Select(Base, member.ContactID);
if (contact != null)
{
CBCRMarketingListMemberExt ext = PXCache<CRMarketingListMember>.GetExtension<CBCRMarketingListMemberExt>(item);
if (ext != null)
{
answer = SelectFrom<CSAnswers>
.Where<CSAnswers.refNoteID.IsEqual<@P.AsGuid>
.And<CSAnswers.attributeID.IsEqual<@P.AsString>>>.View.Select(Base, contact.NoteID, "DEPTCODE");
if (answer != null)
{
detail = SelectFrom<CSAttributeDetail>.Where<CSAttributeDetail.attributeID.IsEqual<@P.AsString>
.And<CSAttributeDetail.valueID.IsEqual<@P.AsString>>>.View.Select(Base, answer.AttributeID, answer.Value);
if (detail != null)
{
ext.UsrDepartment = detail.Description;
}
}

answer = SelectFrom<CSAnswers>
.Where<CSAnswers.refNoteID.IsEqual<@P.AsGuid>
.And<CSAnswers.attributeID.IsEqual<@P.AsString>>>.View.Select(Base, contact.NoteID, "TSRACCOUNT");
if (answer != null)
{
ext.UsrTSRAccount = answer.Value;
}
}
}
yield return item;
}
}

This is my DAC extension:

public sealed class CBCRMarketingListMemberExt : PXCacheExtension<PX.Objects.CR.CRMarketingListMember>
{
#region UsrDepartment
[PXString(255)]
[PXUIField(DisplayName = "Department")]
public string UsrDepartment { get; set; }
public abstract class usrDepartment : PX.Data.BQL.BqlString.Field<usrDepartment> { }
#endregion

#region UsrTSRAccount
[PXString(255)]
[PXUIField(DisplayName = "TSR Account")]
public string UsrTSRAccount { get; set; }
public abstract class usrTSRAccount : PX.Data.BQL.BqlString.Field<usrTSRAccount> { }
#endregion
}

The Department field is a DropDown list Attribute.  So to get that value, I have to do two selects to get the Description of the DDL value.

The TSR Account field is a simple select from the CSAnswers table.

I thought I might have to somehow add these fields to the ListMembers View, but that would be a very complicated override, and I don’t even know if it is possible.

Any thoughts?  Does this have to be done in a View override?

Best answer by Joe Schmucker

I resolved my issue.  I ended up overriding the View.

I needed to pull data from CSAnswers twice, but I could not get that to work.  So I went guerilla and used a SQL View to get the TSR Account field.  

Here is the resulting code:

		[PXOverride]
[PXViewName(Messages.MailRecipients)]
[PXImportSubstitute(typeof(CRMarketingList), typeof(CRMarketingMemberForImport))]
[PXCopyPasteHiddenView]
[PXFilterable]
[PXDependToCache(typeof(CRMarketingList))]
public SelectFrom<CRMarketingListMember>
.InnerJoin<Contact> // for proper tail update
.On<Contact.contactID.IsEqual<CRMarketingListMember.contactID>>
.LeftJoin<ICSTSRAccountView>
.On<ICSTSRAccountView.refNoteID.IsEqual<Contact.noteID>
.And<ICSTSRAccountView.attributeID.IsEqual<ICSTSRATTR>>>
.LeftJoin<CSAnswers>
.On<CSAnswers.refNoteID.IsEqual<Contact.noteID>
.And<CSAnswers.attributeID.IsEqual<ICSDeptATTR>>>
.InnerJoin<CSAttributeDetail>
.On<CSAttributeDetail.attributeID.IsEqual<CSAnswers.attributeID>
.And<CSAttributeDetail.valueID.IsEqual<CSAnswers.value>>>
.OrderBy<
CRMarketingListMember.createdDateTime.Desc,
CRMarketingListMember.isSubscribed.Desc,
Contact.displayName.Asc>.View ListMembers;

// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
[PXNonInstantiatedExtension]
public sealed class CS_CSAttributeDetail_ExistingColumn : PXCacheExtension<PX.Objects.CS.CSAttributeDetail>
{
#region Description
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXUIField(DisplayName = "Department")]
public string Description { get; set; }
#endregion
}


public class ICSTSRAccountView : PXBqlTable, IBqlTable
{
#region RefNoteID
[PXDBGuid()]
[PXUIField(DisplayName = "Ref Note ID")]
public virtual Guid? RefNoteID { get; set; }
public abstract class refNoteID : PX.Data.BQL.BqlGuid.Field<refNoteID> { }
#endregion

#region AttributeID
[PXDBString(10, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Attribute ID")]
public virtual string AttributeID { get; set; }
public abstract class attributeID : PX.Data.BQL.BqlString.Field<attributeID> { }
#endregion

#region Value
[PXDBString(255, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "TSR Account")]
public virtual string Value { get; set; }
public abstract class value : PX.Data.BQL.BqlString.Field<value> { }
#endregion
}

 

2 replies

Joe Schmucker
Captain II
Forum|alt.badge.img+3
  • Author
  • Captain II
  • Answer
  • July 20, 2025

I resolved my issue.  I ended up overriding the View.

I needed to pull data from CSAnswers twice, but I could not get that to work.  So I went guerilla and used a SQL View to get the TSR Account field.  

Here is the resulting code:

		[PXOverride]
[PXViewName(Messages.MailRecipients)]
[PXImportSubstitute(typeof(CRMarketingList), typeof(CRMarketingMemberForImport))]
[PXCopyPasteHiddenView]
[PXFilterable]
[PXDependToCache(typeof(CRMarketingList))]
public SelectFrom<CRMarketingListMember>
.InnerJoin<Contact> // for proper tail update
.On<Contact.contactID.IsEqual<CRMarketingListMember.contactID>>
.LeftJoin<ICSTSRAccountView>
.On<ICSTSRAccountView.refNoteID.IsEqual<Contact.noteID>
.And<ICSTSRAccountView.attributeID.IsEqual<ICSTSRATTR>>>
.LeftJoin<CSAnswers>
.On<CSAnswers.refNoteID.IsEqual<Contact.noteID>
.And<CSAnswers.attributeID.IsEqual<ICSDeptATTR>>>
.InnerJoin<CSAttributeDetail>
.On<CSAttributeDetail.attributeID.IsEqual<CSAnswers.attributeID>
.And<CSAttributeDetail.valueID.IsEqual<CSAnswers.value>>>
.OrderBy<
CRMarketingListMember.createdDateTime.Desc,
CRMarketingListMember.isSubscribed.Desc,
Contact.displayName.Asc>.View ListMembers;

// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
[PXNonInstantiatedExtension]
public sealed class CS_CSAttributeDetail_ExistingColumn : PXCacheExtension<PX.Objects.CS.CSAttributeDetail>
{
#region Description
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXUIField(DisplayName = "Department")]
public string Description { get; set; }
#endregion
}


public class ICSTSRAccountView : PXBqlTable, IBqlTable
{
#region RefNoteID
[PXDBGuid()]
[PXUIField(DisplayName = "Ref Note ID")]
public virtual Guid? RefNoteID { get; set; }
public abstract class refNoteID : PX.Data.BQL.BqlGuid.Field<refNoteID> { }
#endregion

#region AttributeID
[PXDBString(10, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Attribute ID")]
public virtual string AttributeID { get; set; }
public abstract class attributeID : PX.Data.BQL.BqlString.Field<attributeID> { }
#endregion

#region Value
[PXDBString(255, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "TSR Account")]
public virtual string Value { get; set; }
public abstract class value : PX.Data.BQL.BqlString.Field<value> { }
#endregion
}

 


Chris Hackett
Community Manager
Forum|alt.badge.img
  • Acumatica Community Manager
  • July 21, 2025

Thank you for sharing your solution with the community ​@Joe Schmucker!