Filters In Acumatica
Hello everybody,
in this article I want to describe how filtering in Acumatica work. When I say filtering, I mean following UI part:
In manuals T100 - T300 there is almost nothing about how filters work, so I want to share few bits of development information.
Storage
All information about filters is stored in database in tables FilterRow and FilterHeader.
Take a look on screenshot of FilterInformation for some custom applied filter:
As you can see from screenshot Acumatica stores information about filters by FilterID, and has information like Condition, values, Close brackets, operators and so on.
Also there are DAC classes FilterRow and FilterHeader, but you can find them only with help of reflector or any other "spy tool".
Modification
Acumatica allows you to work with filters with help of Search functionality in selector and similar to it ( for example Search2 ). Take a look on declaration of filter of APPayment column RefNbr:
[PXDBString(15, InputMask = ">CCCCCCCCCCCCCCC", IsKey = true, IsUnicode = true)] [PXDefault] [PXUIField(DisplayName = "Reference Nbr.", TabOrder = 1, Visibility = PXUIVisibility.SelectorVisible)] [APInvoiceType.RefNbr(typeof(Search2<APRegisterAlias.refNbr, InnerJoinSingleTable<APInvoice, On<APInvoice.docType, Equal<APRegisterAlias.docType>, And<APInvoice.refNbr, Equal<APRegisterAlias.refNbr>>>, InnerJoinSingleTable<Vendor, On<APRegisterAlias.vendorID, Equal<Vendor.bAccountID>>>>, Where<APRegisterAlias.docType, Equal<Optional<APInvoice.docType>>, And2<Where<APRegisterAlias.origModule, NotEqual<BatchModule.moduleTX>, Or<APRegisterAlias.released, Equal<True>>>, And<Match<Vendor, Current<AccessInfo.userName>>>>>, OrderBy<Desc<APRegisterAlias.refNbr>>>), Filterable = true, IsPrimaryViewCompatible = true)] [APPaymentType.Numbering] [PXFieldDescription]
The same filtering is applied at APInvoice. And now you can ask, ok, so what it gives me? Actually it means that by default, if you make some filter as default for screen of invoices, then the same filter will be default and applied to Bills. If you wonder how to split those siameses twins?
The idea is simple, make your own duplicate of class APRegisterAlias, and via CacheAttached add it to needed screen. Below goes code, that I've used for this purpose:
public class APPaymentEntryExt : PXGraphExtension<APPaymentEntry> { [PXDBString(15, InputMask = ">CCCCCCCCCCCCCCC", IsKey = true, IsUnicode = true)] [PXDefault] [PXUIField(DisplayName = "Reference Nbr.1", TabOrder = 1, Visibility = PXUIVisibility.SelectorVisible)] [APInvoiceType.RefNbr(typeof(Search2<APRegisterAliasSep.refNbr, InnerJoinSingleTable<APInvoice, On<APInvoice.docType, Equal<APRegisterAliasSep.docType>, And<APInvoice.refNbr, Equal<APRegisterAliasSep.refNbr>>>, InnerJoinSingleTable<Vendor, On<APRegisterAliasSep.vendorID, Equal<Vendor.bAccountID>>>>, Where<APRegisterAliasSep.docType, Equal<Optional<APInvoice.docType>>, And2<Where<APRegisterAliasSep.origModule, NotEqual<BatchModule.moduleTX>, Or<APRegisterAliasSep.released, Equal<True>>>, And<Match<Vendor, Current<AccessInfo.userName>>>>>, OrderBy<Desc<APRegisterAliasSep.refNbr>>>), Filterable = true, IsPrimaryViewCompatible = true)] [APPaymentType.Numbering] [PXFieldDescription] protected void APPayment_RefNbr_CacheAttached(PXCache sender) { } } [PXHidden] [PXPrimaryGraph(new[] { typeof(APQuickCheckEntry), typeof(TXInvoiceEntry), typeof(APInvoiceEntry), typeof(APPaymentEntry) }, new[] { typeof(Select<APQuickCheck, Where<APQuickCheck.docType, Equal<Current<APQuickCheck.docType>>, And<APQuickCheck.refNbr, Equal<Current<APQuickCheck.refNbr>>>>>), typeof(Select<APInvoice, Where<APInvoice.docType, Equal<Current<APInvoice.docType>>, And<APInvoice.refNbr, Equal<Current<APInvoice.refNbr>>, And<Where<APInvoice.released, Equal<False>, And<APRegister.origModule, Equal<BatchModule.moduleTX>>>>>>>), typeof(Select<APInvoice, Where<APInvoice.docType, Equal<Current<APInvoice.docType>>, And<APInvoice.refNbr, Equal<Current<APInvoice.refNbr>>>>>), typeof(Select<PX.Objects.AP.APPayment, Where<PX.Objects.AP.APPayment.docType, Equal<Current<PX.Objects.AP.APPayment.docType>>, And<PX.Objects.AP.APPayment.refNbr, Equal<Current<PX.Objects.AP.APPayment.refNbr>>>>>) })] [Serializable] public class APRegisterAliasSep : APRegister { public abstract class selected : IBqlField, IBqlOperand { } public abstract class hidden : IBqlField, IBqlOperand { } public abstract class branchID : IBqlField, IBqlOperand { } public abstract class docType : IBqlField, IBqlOperand { } public abstract class printDocType : IBqlField, IBqlOperand { } public abstract class refNbr : IBqlField, IBqlOperand { } public abstract class origModule : IBqlField, IBqlOperand { } public abstract class docDate : IBqlField, IBqlOperand { } public abstract class origDocDate : IBqlField, IBqlOperand { } public abstract class tranPeriodID : IBqlField, IBqlOperand { } public abstract class finPeriodID : IBqlField, IBqlOperand { } public abstract class vendorID : IBqlField, IBqlOperand { } public abstract class vendorID_Vendor_acctName : IBqlField, IBqlOperand { } public abstract class vendorLocationID : IBqlField, IBqlOperand { } public abstract class curyID : IBqlField, IBqlOperand { } public abstract class aPAccountID : IBqlField, IBqlOperand { } public abstract class aPSubID : IBqlField, IBqlOperand { } public abstract class lineCntr : IBqlField, IBqlOperand { } public abstract class curyInfoID : IBqlField, IBqlOperand { } public abstract class curyOrigDocAmt : IBqlField, IBqlOperand { } public abstract class origDocAmt : IBqlField, IBqlOperand { } public abstract class curyDocBal : IBqlField, IBqlOperand { } public abstract class docBal : IBqlField, IBqlOperand { } public abstract class discTot : IBqlField, IBqlOperand { } public abstract class curyDiscTot : IBqlField, IBqlOperand { } public abstract class docDisc : IBqlField, IBqlOperand { } public abstract class curyDocDisc : IBqlField, IBqlOperand { } public abstract class curyOrigDiscAmt : IBqlField, IBqlOperand { } public abstract class origDiscAmt : IBqlField, IBqlOperand { } public abstract class curyDiscTaken : IBqlField, IBqlOperand { } public abstract class discTaken : IBqlField, IBqlOperand { } public abstract class curyDiscBal : IBqlField, IBqlOperand { } public abstract class discBal : IBqlField, IBqlOperand { } public abstract class curyOrigWhTaxAmt : IBqlField, IBqlOperand { } public abstract class origWhTaxAmt : IBqlField, IBqlOperand { } public abstract class curyWhTaxBal : IBqlField, IBqlOperand { } public abstract class whTaxBal : IBqlField, IBqlOperand { } public abstract class curyTaxWheld : IBqlField, IBqlOperand { } public abstract class taxWheld : IBqlField, IBqlOperand { } public abstract class curyChargeAmt : IBqlField, IBqlOperand { } public abstract class chargeAmt : IBqlField, IBqlOperand { } public abstract class docDesc : IBqlField, IBqlOperand { } public abstract class createdByID : IBqlField, IBqlOperand { } public abstract class createdByScreenID : IBqlField, IBqlOperand { } public abstract class createdDateTime : IBqlField, IBqlOperand { } public abstract class lastModifiedByID : IBqlField, IBqlOperand { } public abstract class lastModifiedByScreenID : IBqlField, IBqlOperand { } public abstract class lastModifiedDateTime : IBqlField, IBqlOperand { } public abstract class Tstamp : IBqlField, IBqlOperand { } public abstract class docClass : IBqlField, IBqlOperand { } public abstract class batchNbr : IBqlField, IBqlOperand { } public abstract class prebookBatchNbr : IBqlField, IBqlOperand { } public abstract class voidBatchNbr : IBqlField, IBqlOperand { } public abstract class released : IBqlField, IBqlOperand { } public abstract class openDoc : IBqlField, IBqlOperand { } public abstract class hold : IBqlField, IBqlOperand { } public abstract class scheduled : IBqlField, IBqlOperand { } public abstract class voided : IBqlField, IBqlOperand { } public abstract class printed : IBqlField, IBqlOperand { } public abstract class prebooked : IBqlField, IBqlOperand { } public abstract class noteID : IBqlField, IBqlOperand { } public abstract class refNoteID : IBqlField, IBqlOperand { } public abstract class closedFinPeriodID : IBqlField, IBqlOperand { } public abstract class closedTranPeriodID : IBqlField, IBqlOperand { } public abstract class rGOLAmt : IBqlField, IBqlOperand { } public abstract class curyRoundDiff : IBqlField, IBqlOperand { } public abstract class roundDiff : IBqlField, IBqlOperand { } public abstract class curyTaxRoundDiff : IBqlField, IBqlOperand { } public abstract class taxRoundDiff : IBqlField, IBqlOperand { } public abstract class status : IBqlField, IBqlOperand { } public abstract class scheduleID : IBqlField, IBqlOperand { } public abstract class impRefNbr : IBqlField, IBqlOperand { } public abstract class isTaxValid : IBqlField, IBqlOperand { } public abstract class isTaxPosted : IBqlField, IBqlOperand { } public abstract class isTaxSaved : IBqlField, IBqlOperand { } public abstract class origDocType : IBqlField, IBqlOperand { } public abstract class origRefNbr : IBqlField, IBqlOperand { } public abstract class releasedOrPrebooked : IBqlField, IBqlOperand { } public abstract class taxCalcMode : IBqlField, IBqlOperand { } public abstract class approved : IBqlField, IBqlOperand { } public abstract class rejected : IBqlField, IBqlOperand { } public abstract class dontApprove : IBqlField, IBqlOperand { } public abstract class employeeWorkgroupID : IBqlField, IBqlOperand { } public abstract class employeeID : IBqlField, IBqlOperand { } public abstract class workgroupID : IBqlField, IBqlOperand { } public abstract class ownerID : IBqlField, IBqlOperand { } public abstract class curyInitDocBal : IBqlField, IBqlOperand { } public abstract class initDocBal : IBqlField, IBqlOperand { } public abstract class displayCuryInitDocBal : IBqlField, IBqlOperand { } public abstract class isMigratedRecord : IBqlField, IBqlOperand { } public abstract class curyDiscountedDocTotal : IBqlField, IBqlOperand { } public abstract class discountedDocTotal : IBqlField, IBqlOperand { } public abstract class curyDiscountedTaxableTotal : IBqlField, IBqlOperand { } public abstract class discountedTaxableTotal : IBqlField, IBqlOperand { } public abstract class curyDiscountedPrice : IBqlField, IBqlOperand { } public abstract class discountedPrice : IBqlField, IBqlOperand { } public abstract class hasPPDTaxes : IBqlField, IBqlOperand { } public abstract class pendingPPD : IBqlField, IBqlOperand { } }
and as result, I've got two filters splitted.