How to use a Multi-Select String field in a BQL Where - acumatica

I have a field in the unbound filter DAC for a custom processing screen that is a multi-select dropdown field. It has the PXStringList attribute defined like this:
#region POStatus
[PXString]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "PO Status")]
[PXStringList(new string[] { "N", "B" }, new string[] { "Open", "Pending Approval" }, MultiSelect =true)]
public string POStatus { get; set; }
public abstract class poStatus : PX.Data.BQL.BqlString.Field<poStatus> { }
#endregion
How can I use this field in the Where clause of the BQL query for the main view? So, in this case I'm trying to filter POOrder records by whatever statuses the user selects in the multi-select drop down.
I tried using the IsIn<> operator but, it doesn't build.
Do I have to resort to a view delegate in order to do this?
TIA!

Acumatica stores the values for the multi-select drop-downs in 1 field as comma-separated values. The first thing I would try would be to try using the Contains operation in opposite direction like below:
PXSelect<POOrder, Where<Current<FilterDAC.poStatus>, Contains<POOrder.status>>> FilteredPOList;

Related

Field filter within the grid

I'm not good at English.
I want to know if it is possible to filter field in grid.
I have a problem I am filtering a field, but it is not updated in selector, where it should show what I want.
here I show an image.
I will thank you all very much.
here I put the code I did:
#region CategoryID
[PXDBInt()]
[PXUIField(DisplayName = "Category ID")]
[PXSelector(typeof(Search<PESKPriceIndexCat.categoryID,
Where<PESKPriceIndexCat.state, Equal<Current<stateID>>,
And<PESKPriceIndexCat.active, Equal<True>>>>),
typeof(PESKPriceIndexCat.categoryID),
typeof(PESKPriceIndexCat.categoryCD),
typeof(PESKPriceIndexCat.descripcion),
DescriptionField = typeof(PESKPriceIndexCat.descripcion), SubstituteKey =
typeof(PESKPriceIndexCat.categoryCD))]
public virtual int? CategoryID { get; set; }
public abstract class categoryID : PX.Data.BQL.BqlInt.Field<categoryID> { }
#endregion
The definition of the selector in the DAC seems to be correct, therefore one possible solution would be to set the AutoRefresh property on the selector from the layout editor to true and the SyncPosition property on the grid to true as well. With these two properties the current value will update on row change and when opening the selector it will automatically refresh with the correct dataset.

How to change the display name of description field of selector

I have a customization where I'm adding a Selector to a grid field that has a description field as follows:
[PXSelector(typeof(Search<EPEmployee.bAccountID,
Where<EPEmployee.status, Equal<SetupTypes.active>>>),
typeof(EPEmployee.acctCD),
typeof(EPEmployee.acctName),
SubstituteKey = typeof(EPEmployee.acctCD),
DescriptionField = typeof(EPEmployee.acctName))]
My problem is that the field has a description (in this case, 'Employee Name') field that is automatically added, but I can't find a way to change the display name of that field.
Since I have another field that uses the same employee lookup, they both have the same 'Employee Name' description field - so I have no way of knowing which description goes with which Selector field unless I choose a value and see the description show up in its associated 'Employee Name' field.
Is there a way to change the display name of that description field? I've tried CacheAttached and the RowSelected event with a PXUIFieldAttribute.SetDisplayName, but nothing seems to work.. seems that 'field_description' is an automatically added field that doesn't exist anywhere in the DAC to be able to change the display name.
Per Acumatica support, the only way that this can be done is as follows:
The only way that seems to work is to have two different DACs that are projections on the EPEmployee DAC and use each in the separate selector attribute.
For instance:
[PXProjection(typeof(EPEmployee))]
public class EPEmployeeTest : IBqlTable
{
#region BAccountID
...
#endregion
#region AcctCD
...
#endregion
public abstract class acctName : PX.Data.BQL.BqlString.Field<acctName> { }
[PXDBString(60, IsUnicode = true, BqlField=typeof(EPEmployee.acctName))]
[PXUIField(DisplayName = "Employee Name New Label", Enabled = false, Visibility = PXUIVisibility.SelectorVisible)]
public override string AcctName{get; set;}
}

Accessing user-defined fields added via an extension in Acumatica

I have a custom field called 'UsrIsTeacherBook` which was added to the InventoryItem with the following extension:
namespace Lasalle.TeacherBooks
{
public class InventoryItem_TeacherBooks_Extension : PXCacheExtension<InventoryItem>
{
[PXDBBool]
[PXUIField(DisplayName = "Is Teacher Book")]
public virtual bool? UsrIsTeacherBook { get; set; }
public abstract class usrIsTeacherBook : IBqlField { }
}
}
I need to be able to access the value of this IsTeacherBook field from the SOLine grid on the SalesOrder screen. I added a custom field UsrTeacherBook to the SOLine grid on the sales order screen, but I cannot figure out how to populate this field with the value of InventoryItem UsrIsTeacherBook.
I tried customizing the attributes on the SOLine field in the following way:
[PXDBBool]
[PXUIField(DisplayName="Teacher Manual", Visible = true, Enabled = false)]
[PXFormula(typeof(Selector<SOLine.inventoryID, InventoryItemExt.usrIsTeacherBook>))]
But this produced a validation error, "The type name 'usrIsTeacherBook' does not exist in the type 'PX.Objects.IN.InventoryItemExt'."
What is the correct way to access the InventoryItem IsTeacherBook field to populate my field on the SOLine grid?
Your extension class name is InventoryItem_TeacherBooks_Extension, not InventoryItemExt used in PXFormulaAttribute. You should either change your extension name to InventoryItemExt or modify PXFormula declaration with InventoryItem_TeacherBooks_Extension.usrIsTeacherBook

Filtering PXselector with search

I have a custom grid using a custom dac that I have declared. Originally i had a PXselector attribute set to POOrder.orderNbr
With this selector it grabs all POOrders in my grid selector
[PXDBString(50, IsKey = true, IsUnicode = true, InputMask = "")]
[PXSelector(typeof(POOrder.orderNbr))]
[PXUIField(DisplayName = "Po#")]
public string Po { get; set; }
public class po : IBqlField { }
But i want the selector to filter POOrders that appear on the Document details->POReceiptLine. I attempted to filter using the Search but only get the lowest value POOrder.ordnbr on the receipt. The images below should illustrate what I mean. I want it to show all POOrder.orderNbr but it's only retrieving the first lowest value order.
[PXDBString(50, IsKey = true, IsUnicode = true, InputMask = "")]
[PXSelector(typeof(Search<POOrder.orderNbr,Where<POOrder.orderNbr,Equal<Current2<POReceiptLine.pONbr>>>>))]
[PXUIField(DisplayName = "Po#")]
public string Po { get; set; }
public class po : IBqlField { }
I believe it would be much better if you inner join POReceiptLine DAC, and then aggregate associated Purchase Orders to eliminate possible duplicates:
[PXSelector(typeof(Search5<POOrder.orderNbr,
InnerJoin<POReceiptLine, On<POReceiptLine.pOType, Equal<POOrder.orderType>,
And<POReceiptLine.pONbr, Equal<POOrder.orderNbr>,
And<POReceiptLine.receiptNbr, Equal<Current<POReceipt.receiptNbr>>>>>>,
Aggregate<GroupBy<POOrder.orderType,
GroupBy<POOrder.orderNbr>>>>))]
The main issue in the selector is that you are looking for POOrder where the order Number equals the current Receipt Line. That means that depending the line selected, the value will change but will always yield only one result. The solution would then be to change the condition to be on the Purchase Receipt document instead.
To do so you have two options. Either you search directly POReceiptLine.poNbr, but then your selector will display columns from that table, or you join POOrder to POReceiptLine.
With search on POReceiptLine
[PXSelector(typeof(Search<POReceiptLine.pONbr,
Where<POReceiptLine.receiptType,
Equal<Optional<POReceipt.receiptType>>,
And<POReceiptLine.receiptNbr,
Equal<Optional<POReceipt.receiptNbr>>>>>), DirtyRead = true)]
With search on POOrder
[PXSelector(typeof(Search2<POOrder.orderNbr,
InnerJoin<POReceiptLine, On<POReceiptLine.pOType,
Equal<POOrder.orderType>,
And<POReceiptLine.pONbr,
Equal<POOrder.orderNbr>>>>,
Where<POReceiptLine.receiptType,
Equal<Optional<POReceipt.receiptType>>,
And<POReceiptLine.receiptNbr,
Equal<Optional<POReceipt.receiptNbr>>>>>))]
Also notice the parameter DirtyRead = true. This parameter will tell the selector to get it's information in the cache and not only from the Database. Because you are selecting something from the same page, you would need to save the whole document before being able to select the record otherwise. Unfortunatly it would not work with the second option because the Join is done at the database level.

BQL subquery in the where clause

Hi I am having trouble some BQL syntax what I want to achieve is a BQL statement like the below SQL with nested sub query in the where clause.
SELECT * FROM ARInvoice I
WHERE (SELECT COUNT(*) FROM ARAdjust A WHERE I.RefNbr = A.AdjdRefNbr) > 0
Is this possible in BQL if so how would I write this?
Below is what I have got at the moment but this isn't correct I'm getting syntax errors
PXSelect<PX.Objects.AR.ARInvoice,
Where<PXSelectGroupBy<PX.Objects.AR.ARAdjust, Where<PX.Objects.AR.ARAdjust.adjdRefNbr, Equal<PX.Objects.AR.ARInvoice.refNbr>, Aggregate<Count>>, Greater<Zero>>>>.Select(new PXGraph());
thanks
You have two options to implement this.
Using Sub Queries:
You could add an unbound calculated field (PXDBScalar) in your ARInvoice
To add Sub Queries in BQL, you must do it at the the attribute level. Because you want to query another table, PXDBScalar, would be the best option. If you wanted to query other fields of the same record, PXDBCalced would be more adequate. For more informations about Advanced SQL Attributes please refer to the T200 under Using Advanced SQL Attributes and Acumatica’s help under Help -> Acumatica Framework -> API Reference -> Attributes -> Adhoc SQL for Fields.
Extend the ARInvoice (V5.1 and below)
public class ARInvoiceExtension : PXCacheExtension<ARInvoice>
{
public abstract class lastPaymentOrderNbr : IBqlField
{
}
#region LastPaymentOrderNbr
[PXString]
[PXUIField(DisplayName = "Last Payment Order Nbr.")]
[PXDBScalar(typeof(Search<ARAdjust.adjdOrderNbr,
Where<ARAdjust.adjdDocType, Equal<ARInvoice.docType>,
And<ARAdjust.adjdRefNbr, Equal<ARInvoice.refNbr>>>,
OrderBy<Desc<ARAdjust.adjgDocDate>>>))]
public string LastPaymentOrderNbr { get; set; }
#endregion
}
A new field has been added to ARInvoice in V5.2 to get the last payment date so you don't have to add another one:
public abstract class lastPaymentDate : PX.Data.IBqlField
{
}
protected DateTime? _LastPaymentDate;
/// <summary>
/// The date of the most recent payment associated with this document.
/// </summary>
[PXDate()]
[PXDBScalar(typeof(Search<ARAdjust.adjgDocDate,
Where<ARAdjust.adjdDocType, Equal<ARInvoice.docType>,
And<ARAdjust.adjdRefNbr , Equal<ARInvoice.refNbr>>>,
OrderBy<Desc<ARAdjust.adjgDocDate>>>))]
[PXUIField(DisplayName = "Last Payment Date")]
public virtual DateTime? LastPaymentDate
{
get
{
return this._LastPaymentDate;
}
set
{
this._LastPaymentDate = value;
}
}
Your PXSelect would then look like this:
V5.1 and below
public PXSelect<ARInvoice, Where<ARInvoiceExtension.lastPaymentOrderNbr, IsNotNull>> InvoicesTest;
V5.2
public PXSelect<ARInvoice, Where<ARInvoice.lastPaymentDate, IsNotNull>> InvoicesTest;
Inner join on table
Instead of sub-querying it you could simply add an inner join and filter record that do not have an ARAdjust. You then group by your key fields to avoid duplicates.
public PXSelectJoinGroupBy<ARInvoice,
InnerJoin<ARAdjust, On<ARAdjust.adjdRefNbr, Equal<ARInvoice.refNbr>,
And<ARAdjust.adjdDocType, Equal<ARInvoice.docType>>>>,
Where<ARAdjust.adjdOrderNbr, IsNotNull>,
Aggregate<GroupBy<ARInvoice.docType,
GroupBy<ARInvoice.refNbr>>>> InvoicesTest;

Resources