I want to add Attributes on InventoryID lookup on POLine. I have written below code and in adding a column on InventoryId Lookup. I want to make the attribute field filterable. I am not sure how to do it. Can anyone please help me with this? And also I wanted to add the same filterable for InventoryId on ADD Item lookup on PO Screen.
public class PXAddAtttributeColumns : CRAttributesFieldAttribute
{
string[] _names;
public PXAddAtttributeColumns(string[] names, Type classID,
Type noteID)
: base(classID, noteID)
{
_names = names;
}
public override void CacheAttached(PXCache sender)
{
this._IsActive = true;
base.CacheAttached(sender);
}
protected override void AttributeFieldSelecting(PXCache sender, PXFieldSelectingEventArgs e, PXFieldState state, string attributeName, int idx)
{
if (_names.Any(attributeName.Equals))
{
state.DisplayName = (!String.IsNullOrEmpty(state.DisplayName)) ? (state.DisplayName.Replace("$Attributes$-", "")) : attributeName;
state.Visible = true;
state.Visibility = PXUIVisibility.Dynamic;
}
base.AttributeFieldSelecting(sender, e, state, attributeName, idx);
}
}
public class InventoryItemExt : PXCacheExtension<PX.Objects.IN.InventoryItem>
{
public abstract class itemAttributes : IBqlField { }
[InventoryItemMaint_Extension.PXAddAtttributeColumns(new[] {
"COLOR" },
typeof(InventoryItem.itemClassID),
typeof(InventoryItem.noteID))]
public virtual string[] ItemAttributes { get; set; }
}
You can set FastFilterFields property for the POLine grid to make the attribute column filterable.
Example: FastFilterFields="COLOR_ItemAttributes"
This should allow you to filter the grid based on your attribute column in InventoryID lookup.
Related
I am trying to update the dropdown values for Reason field in Cases if Status is set to Open.
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (CRCase)e.Row;
if (row == null) return;
if (row.Status == CRCaseStatusesAttribute._OPEN)
{
PXStringListAttribute.SetList<CRCase.resolution>(cache, row,
new string[] { "IP", "AD", "ES", "QQ", "CC" },
new string[] { "In Process", "Updated", "In Escalation", "Pending Quote", "Pending Closure"}
);
}
}
But it doesn't seem to be reflecting on the UI.
I checked if anything else is overriding my code in CRCaseMaint graph but couldn't find any which seem to be affecting the List.
I couldn't see anything off in Field definition though.
#region Resolution
public abstract class resolution : PX.Data.BQL.BqlString.Field<resolution> { }
[PXDBString(2, IsFixed = true)]
[CRCaseResolutions]
[PXUIField(DisplayName = "Reason")]
[PXChildUpdatable]
[PXMassUpdatableField]
public virtual String Resolution { get; set; }
#endregion
public sealed class CRCaseResolutionsAttribute : PXStringListAttribute
{
public const string _CUSTOMER_PRECLOSED = "CC";
public const string _CUSTOMER_REPLIED = "AD";
public const string _RESOLVED = "RD";
public const string _ASSIGNED = "AS";
public const string _UNASSIGNED = "UA";
public const string _UPDATED = "AD";
public CRCaseResolutionsAttribute();
public sealed class CustomerPreclosed : BqlType<IBqlString, string>.Constant<CustomerPreclosed>
{
public CustomerPreclosed();
}
public sealed class CustomerReplied : BqlType<IBqlString, string>.Constant<CustomerReplied>
{
public CustomerReplied();
}
public sealed class Resolved : BqlType<IBqlString, string>.Constant<Resolved>
{
public Resolved();
}
public sealed class Assigned : BqlType<IBqlString, string>.Constant<Assigned>
{
public Assigned();
}
public sealed class Unassigned : BqlType<IBqlString, string>.Constant<Unassigned>
{
public Unassigned();
}
public sealed class Updated : BqlType<IBqlString, string>.Constant<Updated>
{
public Updated();
}
}
I think I can definitely use different labels and values than the one listed above. Is there anything else that I am missing and/or need to look into?
Note: Acumatica 2019 R1 (Build 19.112.0045) is the version that I am working on.
I have a button in which, when pressed, I want to show or hide rows in a grid based on certain criteria. Is it possible to change the PXSelect a view uses on the fly so that it re-queries the database and retrieves different results? I will, of course, be querying the same table and not changing up the structure of the View or grid.
The code below adds a non-visible field to the header record that is set by the button press this value is then used by the child records view delegate to determine based on the child records criteria (in this case a Boolean on each child) if they are shown.
public sealed class APInvoiceExtension : PXCacheExtension<APInvoice>
{
#region UsrShowAll
public abstract class usrShowAll : IBqlField
{
}
[PXBool]
public bool? UsrShowAll { get; set; }
#endregion
}
public sealed class APTranExtension : PXCacheExtension<APTran>
{
#region UsrHidden
public abstract class usrHidden : IBqlField
{
}
[PXDBBool]
[PXUIField(DisplayName = "Hidden", Enabled = false)]
public bool? UsrHidden { get; set; }
#endregion
}
public class APInvoiceEntryExtension : PXGraphExtension<APInvoiceEntry>
{
public PXAction<APInvoice> SHW;
[PXUIField(DisplayName = "Show All Records", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Update)]
[PXButton]
protected void sHW()
{
if (Base.Document.Current != null)
{
APInvoiceExtension docExt = Base.Document.Current.GetExtension<APInvoiceExtension>();
docExt.UsrShowAll = !(docExt.UsrShowAll ?? false);
}
}
protected virtual IEnumerable transactions()
{
bool showAll = Base.Document.Current != null ? (Base.Document.Current.GetExtension<APInvoiceExtension>().UsrShowAll ?? false) : false;
APTran tran;
foreach (PXResult<APTran, POReceiptLine> res in Base.Transactions.Select())
{
tran = res[0] as APTran;
if (!showAll)
{
if (!(tran.GetExtension<APTranExtension>().UsrHidden ?? false))
{
yield return res;
}
}
else
{
yield return res;
}
}
}
}
I'm trying to populate this field with the value of a customer attribute.
public class CustomerExt : PXCacheExtension<Customer>
{
#region OtherID
[PXString]
[PXUIField(DisplayName = "Other ID")]
[PXDBScalar(typeof(Search<CSAnswers.value,
Where<CSAnswers.refNoteID, Equal<Current<Customer.noteID>>,
And<CSAnswers.attributeID, Like<OtherIDAttr>>>>))]
public virtual string UsrOtherID { get; set; }
public abstract class usrOtherID : IBqlField { }
#endregion
public class OtherIDAttr: Constant<string>
{
public OtherIDAttr() : base("OTHERID") { }
}
}
It causes the above error when the field is added to a screen. If I remove the second condition from the Search<>, the field populates, so I'm sure its the comparison between the CSAnswers AttributeID and the constant string.
If someone could point me in the right direction, that would be awesome.
Looks like you get this error due to the Current operator (Equal<Current<Customer.noteID>>) used within PXDBScalarAttribute.
Attempt to simply remove the Current operator led to a different error Invalid column name 'NoteID'., which can be resolved by the replacement of Customer.noteID with PX.Objects.CR.BAccount.noteID:
public class CustomerExt : PXCacheExtension<Customer>
{
#region OtherID
public abstract class usrOtherID : IBqlField { }
[PXString]
[PXUIField(DisplayName = "Other ID")]
[PXDBScalar(typeof(Search<CSAnswers.value,
Where<CSAnswers.refNoteID, Equal<BAccount.noteID>,
And<CSAnswers.attributeID, Like<OtherIDAttr>>>>))]
public virtual string UsrOtherID { get; set; }
#endregion
public class OtherIDAttr : Constant<string>
{
public OtherIDAttr() : base("OTHERID") { }
}
}
I have extended a APTran DAC for Bills and Adjustments screen (ID - AP301000).
I am trying to populate a value from different table based on the current line item.
The value I need is from CrossReference based on current Inventory on line item and VendorID of current Bill.
Below is the code. Please let me know if I am missing anything.
public class string_VendorType : Constant<string>
{
public string_VendorType() : base("0VPN")
{ }
}
protected string _UsrVendorPartNum;
[PXString(50)]
[PXUIField(DisplayName = "Vendor Part Number", Enabled = false, IsReadOnly = true)]
[PXDefault(typeof(Search2<INItemXRef.alternateID,
LeftJoin<InventoryItem, On<INItemXRef.inventoryID, Equal<InventoryItem.inventoryID>>,
LeftJoin<APTran, On<InventoryItem.inventoryID, Equal<APTran.inventoryID>>,
LeftJoin<APInvoice, On<APInvoice.refNbr, Equal<APTran.refNbr>,
And<APInvoice.vendorID, Equal<INItemXRef.bAccountID>>>>>>,
Where<InventoryItem.inventoryID, Equal<Current<APTran.inventoryID>>,
And<INItemXRef.alternateType, Equal<string_VendorType>,
And<APInvoice.refNbr, Equal<Current<APTran.refNbr>>>>>>))]
public virtual string UsrVendorPartNum
{
get
{
return _UsrVendorPartNum;
}
set
{
_UsrVendorPartNum = value;
}
}
public abstract class usrVendorPartNum : IBqlField { }
However, the value isn't populating. Please advise.
I got the following working (using PXUnboundDefault). The query you have can be simplified to the following working example:
public class APTranExt : PXCacheExtension<PX.Objects.AP.APTran>
{
protected string _UsrVendorPartNum;
[PXString(50)]
[PXUIField(DisplayName = "Vendor Part Number", Enabled = false, IsReadOnly = true)]
[PXUnboundDefault(typeof(Search<INItemXRef.alternateID,
Where<INItemXRef.inventoryID, Equal<Current<APTran.inventoryID>>,
And<INItemXRef.alternateType, Equal<INAlternateType.vPN>,
And<INItemXRef.bAccountID, Equal<Current<APTran.vendorID>>>>>>))]
public virtual string UsrVendorPartNum
{
get
{
return _UsrVendorPartNum;
}
set
{
_UsrVendorPartNum = value;
}
}
public abstract class usrVendorPartNum : IBqlField { }
}
Note that you do not need to create your own constant. You can reuse INAlternateType and the vPN constant.
Simply for reference...
I would say if this was a DB field you could look into using the AlternativeItemAttribute, however it requires a subitem field which oddly APTran does not have in it.
Example usage of AlternativeItemAttribute on POLine.AlternateID:
public abstract class alternateID : PX.Data.IBqlField
{
}
protected String _AlternateID;
[AlternativeItem(INPrimaryAlternateType.VPN, typeof(POLine.vendorID), typeof(POLine.inventoryID), typeof(POLine.subItemID))]
public virtual String AlternateID
{
get
{
return this._AlternateID;
}
set
{
this._AlternateID = value;
}
}
I want to add the attributes for my inventory lookup on Sales Order and Purchase Order, does anyone know how to? or any ideas?
Please refer below code example to include Attributes Columns in Selector and Grid Control utilizing out-of-box CRAttributesFieldAttribute.
Declare a class PXAddAtttributeColumns inherited from CRAttributesFieldAttribute.
public class PXAddAtttributeColumns : CRAttributesFieldAttribute
{
string[] _names;
bool _IsForSelector;
public PXAddAtttributeColumns(string[] names, Type entityType, Type entityIDField, Type classIDField, bool IsForSelector = true)
: base(entityType, entityIDField, classIDField)
{
_names = names;
_IsForSelector = IsForSelector;
}
public override void CacheAttached(PXCache sender)
{
this._IsActive = true;
base.CacheAttached(sender);
}
protected override void AttributeFieldSelecting(PXCache sender, PXFieldSelectingEventArgs e, PXFieldState state, string attributeName, int idx)
{
if (_names.Any(attributeName.Equals))
{
//Out-of-box DisplayName is prefixed with "$Attributes$-" - if you need to take that off.
state.DisplayName = (!String.IsNullOrEmpty(state.DisplayName)) ? (state.DisplayName.Replace("$Attributes$-", "")) : attributeName;
state.Visible = true;
//Requires AutoGenerateColumns="AppendDynamic" for PXGrid Control for dynamic Attribute columns creation
state.Visibility = (_IsForSelector) ? PXUIVisibility.SelectorVisible : PXUIVisibility.Dynamic;
}
base.AttributeFieldSelecting(sender, e, state, attributeName, idx);
}
public override void CommandPreparing(PXCache sender, PXCommandPreparingEventArgs e)
{
base.CommandPreparing(sender, e);
if (e.BqlTable == null && aggregateAttributes && sender.GetItemType().IsDefined(typeof(PXProjectionAttribute), true))
{
e.BqlTable = _BqlTable;
}
}
}
To include attributes as Columns in Inventory Look up, declare DAC Extension as below:
public class InventoryItemPXExt : PXCacheExtension<PX.Objects.IN.InventoryItem>
{
#region Attributes
public abstract class attributes : IBqlField { }
[PXAddAtttributeColumns(new[] { "ASSETID", "HWMODEL" },
typeof(CSAnswerType.inventoryAnswerType),
typeof(InventoryItem.inventoryID),
typeof(InventoryItem.itemClassID))]
public virtual string[] Attributes { get; set; }
#endregion
}
Fields will show up as below:
Search can be Enabled on Attribute Columns by setting FilterByAllFields to True
To include attributes as Columns in Sales Order Details Grid, declare DAC Extension as below:
public class SOLineExtension : PXCacheExtension<SOLine>
{
public abstract class itemAttributes : IBqlField { }
[PXAddAtttributeColumns(new[] { "ASSETID", "HWMODEL" },
typeof(CSAnswerType.inventoryAnswerType),
typeof(SOLine.inventoryID),
typeof(InventoryItem.itemClassID), false)]
public virtual string[] ItemAttributes { get; set; }
}
Make sure to specify AutoGenerateColumns="AppendDynamic" for PXGrid control dynamic Attribute columns creation
Fields will show up as below:
To include attributes as Columns in grid of Add Stock Item Dialog, declare DAC Extension as below:
public class SOSiteStatusSelectedExtension : PXCacheExtension<SOSiteStatusSelected>
{
public abstract class itemAttributes : IBqlField { }
[PXAddAtttributeColumns(new[] { "ASSETID", "HWMODEL" },
typeof(CSAnswerType.inventoryAnswerType),
typeof(InventoryItem.inventoryID),
typeof(InventoryItem.itemClassID), false)]
public virtual string[] ItemAttributes { get; set; }
}
Make sure to specify AutoGenerateColumns="AppendDynamic" for PXGrid control dynamic Attribute columns creation
Fields will show up as below:
Note: This example is applicable to 5.3 series – Build 5.30.1367 onwards.
Updated solution for versions later than 20R1:
Below is the sample scenario to add custom attributes to both CustomerID and InventoryID lookups of Sales Orders (SO301000) screen.
Create the required attributes from Attributes (CS205000) screen.
Add the necessary attribute to the corresponding Customer Classes (AR201000) screen to be added to the CustomerID lookup and to the corresponding Item Classes (IN201000) screen to be added to the InventoryID lookup.
Create a new Attribute class CustomerAttributeSetFieldsAttribute extending CustomerActiveAttribute (since it is used in CustomerID) and override SetColumns by rewriting the same in order to change the FieldList and HeaderList.
public class CustomerAttributeSetFieldsAttribute : CustomerActiveAttribute
{
public static void SetColumns(PXCache cache, string field, string[] fieldList, string[] headerList)
{
PXSelectorAttribute.SetColumns(cache, field, fieldList, headerList);
foreach (CustomerAttributeSetFieldsAttribute attr in cache.GetAttributes(field).OfType<CustomerAttributeSetFieldsAttribute>())
{
attr._FieldList = fieldList;
attr._HeaderList = headerList;
}
}
}
Override Initialize method and call Activate for activating the attribute by passing proper cache - BAccountR - for CustomerID and InventoryItem - for InventoryID. Also, call SetColumns from the custom attribute for CustomerID CustomerAttributeSetFieldsAttribute and PXSelectorAttribute for InventoryID and pass the cache type (where the lookup is present), field (field name), fieldList (list of names of all the fields including the attributes) and headerList (list of names of all the headers including the attributes).
Override the attributes to merge the newly added attribute to CustomerID by adding CustomerAttributeSetFields to SOOrder_CustomerID_CacheAttached method.
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public override void Initialize()
{
base.Initialize();
//for InventoryID lookup
CR.CRAttributesFieldAttribute.Activate(Base.Caches[typeof(InventoryItem)]);
PXSelectorAttribute.SetColumns(Base.Caches[typeof(SOLine)],
"InventoryID", new string[] { "InventoryCD", "Descr", "itemClassID", "Color_ATTRIBUTES" },
new string[] { "InventoryCD", "Descr", "itemClassID", "$Attributes$-Color" });
//for CustomerID lookup
CR.CRAttributesFieldAttribute.Activate(Base.Caches[typeof(BAccountR)]);
CustomerAttributeSetFieldsAttribute.SetColumns(Base.Caches[typeof(SOOrder)],
"CustomerID", new string[] { "AcctCD", "acctName", "COMPREV_Attributes" },
new string[] { "AcctCD", "acctName", "$Attributes$-Company Revenue" });
}
[PXMergeAttributes(Method = MergeMethod.Merge)]
[CustomerAttributeSetFields]
protected virtual void SOOrder_CustomerID_CacheAttached(PXCache sender)
{
}
}
Note: Since Customer DAC is derived from BAccount and CustomerActive attribute is derived from Customer, it has the cache type BAccountR and only the attributes which are of the same cache type are available to add to the CustomerID popup. If the user needs to add other attributes of different cache type, it will be better to create a new Attribute and use that instead of CustomerActive.