How can I set an Attribute as a Parameter in Acumatica Report Designer? - acumatica

I have created an attribute for Stock Item screen, I want that attribute as a parameter in my report .rpx file. My attribute is of combo type attribute.

I wrote a small customization which shows how to add a specific attribute to the report parameter.
First create a custom DAC. In my case, I chose to expose the INDUSTRY attribute.
public class IndustryAttr : IBqlTable
{
#region UsrIndustry
[PXDBString]
[PXUIField(DisplayName = "Industry")]
[PXSelector(typeof(Search<CSAttributeDetail.valueID,
Where<CSAttributeDetail.attributeID,Equal<ind>>>),
typeof(CSAttributeDetail.valueID),
typeof(CSAttributeDetail.description))]
public virtual string UsrIndustry { get; set; }
public abstract class usrIndustry : PX.Data.BQL.BqlString.Field<usrIndustry> {}
#endregion
}
public class ind : PX.Data.BQL.BqlString.Constant<ind>
{
public ind()
: base("INDUSTRY")
{
}
}
Next I added the parameter in the report. Pay attention to the attribute declaration.
Now the Industry attribute appears as the selector

Related

Add Attribute in “Add Item” dialog box in Purchase Order screen of Acumatica

How can I add an Attribute column from "Stock Items" screen to "Add Item" dialog box of Purchase Order screen. I want to add the following attribute from Stock Items screen to the "Add Item" Dialog box of Purchase Order Screen.
Please review the images below for Stock Item and Purchase Order Screens.
I am able to get the field in the inventory lookup of PO, the values did not populated.
here goes my code....
namespace PX.Objects.PO
{
[PXProjection(typeof(Select<CSAnswers, Where<CSAnswers.refNoteID, Equal<POSiteStatusSelected.noteID>,
And<CSAnswers.attributeID, Equal<AttribMyAttribute>>>>), Persistent = false)]
public class POSiteStatusSelectedExt : PXCacheExtension<PX.Objects.PO.POSiteStatusSelected>
{
#region UsrItemType
[PXDBString(10, IsFixed = true, BqlField = typeof(CSAnswers.value))]
[PXUIField(DisplayName = "Item Type")]
//[PXDBScalar(typeof(Search<CSAnswers.value, Where<CSAnswers.refNoteID, Equal<POSiteStatusSelected.noteID>,
// And<CSAnswers.attributeID, Equal<AttribMyAttribute>>>>))]
public virtual string UsrItemType { get; set; }
public abstract class usrItemType : IBqlField { }
#endregion
}
public class AttribMyAttribute : Constant<string>
{
public AttribMyAttribute() : base("ITEMTYPE") { }
}
}
I have created a DAC extension of POSiteStatusSeleted view and added my custom field which is a non-persisted field. There is noteId field in the POSiteStatusSeleted which is of type InventoryItem.noteID, i tried to use the same in the PXDBScalar attribute(the code line is commented), this also didn't work out, it was showing an error for "Unable to convert System.Int32 to System.String".
Updated Answer: Because of the projection, we have to create a new class that inherits the DAC and uses the [PXSubstitute] attribute. The nature of PXSubstitute means that this will not be a DAC extension or even part of a Graph Extension. In my testing, I tried encapsulating this in a graph extension on POOrderEntry, and it did not work. By following the instructions of the stack overflow post below, I was able to create an Attribute called ITEMTYPE, assign it to one of my Item Classes, replace the PXProjection with an enhanced version that includes a left join back to the attribute table (CSAnswers) and then add it to the screen's smart panel grid.
Extend Acumatica Projection Based DAC Query
In the code sample below, the magic is in PXSubstitute, which will take the new class that you create and inherit from the base DAC and replace that base DAC with your new one. If you specify a graph, it will perform the substitution in only that graph (or each graph you specify - 1 per PXSubstitute attribute used). If you do not specify a graph, it will override the base DAC in every case it is used within the xRP Framework.
Code to perform the stated modification:
using PX.Data;
using PX.Objects.AP;
using PX.Objects.Common.Bql;
using PX.Objects.CS;
using PX.Objects.IN;
using System;
namespace PX.Objects.PO
{
[System.SerializableAttribute()]
[PXProjection(typeof(Select2<InventoryItem,
LeftJoin<CSAnswers,
On<CSAnswers.refNoteID, Equal<InventoryItem.noteID>,
And<CSAnswers.attributeID, Equal<AttribItemType>>>,
LeftJoin<INSiteStatus,
On<INSiteStatus.inventoryID, Equal<InventoryItem.inventoryID>, And<INSiteStatus.siteID, NotEqual<SiteAttribute.transitSiteID>>>,
LeftJoin<INSubItem,
On<INSiteStatus.FK.SubItem>,
LeftJoin<INSite,
On<INSiteStatus.FK.Site>,
LeftJoin<INItemXRef,
On<INItemXRef.inventoryID, Equal<InventoryItem.inventoryID>,
And2<Where<INItemXRef.subItemID, Equal<INSiteStatus.subItemID>,
Or<INSiteStatus.subItemID, IsNull>>,
And<Where<CurrentValue<POSiteStatusFilter.barCode>, IsNotNull,
And<INItemXRef.alternateType, Equal<INAlternateType.barcode>>>>>>,
LeftJoin<INItemPartNumber,
On<INItemPartNumber.inventoryID, Equal<InventoryItem.inventoryID>,
And<INItemPartNumber.alternateID, Like<CurrentValue<POSiteStatusFilter.inventory_Wildcard>>,
And2<Where<INItemPartNumber.bAccountID, Equal<Zero>,
Or<INItemPartNumber.bAccountID, Equal<CurrentValue<POOrder.vendorID>>,
Or<INItemPartNumber.alternateType, Equal<INAlternateType.cPN>>>>,
And<Where<INItemPartNumber.subItemID, Equal<INSiteStatus.subItemID>,
Or<INSiteStatus.subItemID, IsNull>>>>>>,
LeftJoin<INItemClass,
On<InventoryItem.FK.ItemClass>,
LeftJoin<INPriceClass,
On<INPriceClass.priceClassID, Equal<InventoryItem.priceClassID>>,
LeftJoin<Vendor,
On<Vendor.bAccountID, Equal<InventoryItem.preferredVendorID>>,
LeftJoin<INUnit,
On<INUnit.inventoryID, Equal<InventoryItem.inventoryID>,
And<INUnit.unitType, Equal<INUnitType.inventoryItem>,
And<INUnit.fromUnit, Equal<InventoryItem.purchaseUnit>,
And<INUnit.toUnit, Equal<InventoryItem.baseUnit>>>>>>>>>>>>>>>,
Where2<CurrentMatch<InventoryItem, AccessInfo.userName>,
And2<Where<INSiteStatus.siteID, IsNull, Or<INSite.branchID, IsNotNull, And2<CurrentMatch<INSite, AccessInfo.userName>,
And<Where2<FeatureInstalled<FeaturesSet.interBranch>,
Or2<SameOrganizationBranch<INSite.branchID, Current<POOrder.branchID>>,
Or<CurrentValue<POOrder.orderType>, Equal<POOrderType.standardBlanket>>>>>>>>,
And2<Where<INSiteStatus.subItemID, IsNull,
Or<CurrentMatch<INSubItem, AccessInfo.userName>>>,
And<InventoryItem.stkItem, Equal<boolTrue>,
And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.inactive>,
And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.unknown>,
And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.markedForDeletion>,
And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.noPurchases>>>>>>>>>>), Persistent = false)]
//[PXSubstitute(GraphType = typeof(POOrderEntry))]
[PXSubstitute]
public partial class POSiteStatusSelectedCst : POSiteStatusSelected
{
#region UsrItemType
[PXDBString(10, BqlField = typeof(CSAnswers.value))]
[PXUIField(DisplayName = "Item Type")]
public string UsrItemType { get; set; }
public abstract class usrItemType : PX.Data.BQL.BqlString.Field<usrItemType> { }
#endregion
}
public class AttribItemType : PX.Data.BQL.BqlString.Constant<AttribItemType>
{
public AttribItemType() : base("ITEMTYPE") { }
}
}

Acumatica : Switching Selector Attribute on the same DAC Field

Good Day!
I have a field in my DAC where I need to change the Selector attribute depending on the setup that I set on my preferences. As you may know, there is an existing LeadSelector Attribute and CustomerSelector Attribute on acumatica. I wish to change the selector attribute of that given field if I set Customer on my preferences, and vice versa.
Is there any available resources right here now?
I've been thinking of creating an Extended Selector attribute on which I will check what is the preference setup then inherit the LeadSelector or CustomerSelector on the Extended Selector. But I think it might not be possible.
The other thing that I've been thinking, is to add both selectors on the attribute and remove them from the graph level whenever which preference is set up.
I'm also thinking of creating 2 selectors, on which I will hide the other depending on the preference setup. But the problem is, the selector is being used not only on one page, and it's a hassle if I create 2 selectors just to solve that issue. And also in the future it might not just lead and customer selectors.
I hope you can help me, I'm out of ideas. Thank you so much.
UPDATE 09-24-2019
I created a custom selector attribute for Lead and Customer Selector attributes. And it's working just I want it to be, but now my problem is, the description field won't show on the text box or on that field, also, there are error such as 'Investor name cannot be found in the system'.
Investor Selector Attribute
public class InvestorSelectorAttribute : PXCustomSelectorAttribute
{
public InvestorSelectorAttribute() : base(typeof(REInvestor.accountID))
{
DescriptionField = typeof(REInvestor.acctName);
SubstituteKey = typeof(REInvestor.acctName);
}
protected IEnumerable GetRecords()
{
var leads = new PXSelect<Contact,
Where<Contact.contactType, Equal<ContactTypesAttribute.lead>,
Or<Where<Contact.contactType, Equal<ContactTypesAttribute.person>,
And<Contact.status, Equal<LeadStatusesAttribute.converted>>>>>>(this._Graph);
var contacts = new PXSelect<BAccountR>(this._Graph);
REFeature setup = PXSelect<REFeature>.Select(this._Graph);
if (setup.InvestorType == InvestorTypesAttribute.LeadVal)
{
foreach (Contact lead in leads.Select())
{
yield return new REInvestor { AccountID = lead.ContactID, AcctName = lead.DisplayName };
}
}
else
{
foreach (BAccountR contact in contacts.Select())
{
yield return new REInvestor { AccountID = contact.BAccountID, AcctName = contact.AcctName, AcctCD = contact.AcctCD };
}
}
}
}
Unbound REInvestor DAC
[Serializable]
[PXCacheName("Investor")]
public class REInvestor : IBqlTable
{
public abstract class accountID : BqlInt.Field<accountID> { }
[PXDBInt(IsKey = true)]
[PXUIField(DisplayName = REMessages.DisplayNames.AccountID, Visibility = PXUIVisibility.SelectorVisible)]
public virtual int? AccountID { get; set; }
public abstract class acctName : BqlString.Field<acctName> { }
[PXDBString(128, InputMask = "", IsUnicode = true)]
[PXUIField(DisplayName = REMessages.DisplayNames.AccountName, Visibility = PXUIVisibility.SelectorVisible)]
public virtual string AcctName { get; set; }
public abstract class acctCD : BqlString.Field<acctCD> { }
[PXDBString(128, InputMask = "", IsUnicode = true)]
[PXUIField(DisplayName = REMessages.DisplayNames.AcctCD, Visibility = PXUIVisibility.SelectorVisible)]
public virtual string AcctCD { get; set; }
}
** DAC Integration **
[PXDBInt]
[PXUIField(DisplayName = REMessages.DisplayNames.InvestorsName, Required = true)]
[InvestorSelector()]
[PXDefault(PersistingCheck = PXPersistingCheck.NullOrBlank)]
public virtual int? ContactID { get; set; }
I really need your help and suggestions. Thank you so much.
Is ok to have 2 fields defined and one displayed.
Each one with his own selector, and PXUIField Description.
You set visibility for one of them base on the setup field at graph level (RowSelected event)
In case you need to merge them on persist (persist both fields in one bound field), you can simply use 2 unbound fields for collecting/displaying data.
on updating/persisting event, you can update the values from unbound fields to unique database field
on retrieve you can make an Data View - Delegate to populate the unbound fields base on configuration;
When you plan to move on multiple pages (graphs) you move the code from the graph to an PXEventSubscriberAttribute
You add the new attribute at the DAC level.
This way you have access on all Graph events that may need (persisting, selecting, updating, ...). All the code stays in one place.
For multiple DACs you still need to create the fields; add them the new attribute.

How to change the Display Name for one of the PXSelector fields

I need to change the Display Name to "Primary Vendor" for a BAccount.acctName field, which is the last field to display in the PXSelector that I have created.
I have tried creating an field Extension which does the trick, but this option also renames the field for another inquiry page, therefore I cannot use it.
The following is my code:
Selector
[PXNonInstantiatedExtension]
public class SO_SOLine_ExistingColumn :
PXCacheExtension<PX.Objects.SO.SOLine>
{
#region InventoryID
[PXMergeAttributes(Method =
MergeMethod.Append)]
[PXSelector(typeof(Search2<InventoryItem.inventoryCD,
LeftJoin<BAccount, On<BAccount.bAccountID,
Equal<InventoryItem.preferredVendorID>>>,
Where<InventoryItem.descr, IsNotNull>>),
typeof(InventoryItem.inventoryID),
typeof(InventoryItem.inventoryCD),
typeof(InventoryItem.descr),
typeof(InventoryItem.postClassID),
typeof(InventoryItem.itemStatus),
typeof(InventoryItem.itemType),
typeof(InventoryItem.baseUnit),
typeof(InventoryItem.salesUnit),
typeof(InventoryItem.purchaseUnit),
typeof(InventoryItem.basePrice),
typeof(BAccount.acctName), ValidateValue = false) ]
public int? InventoryID { get; set; }
#endregion
}
Field Extension
public class BAccountExt : PXCacheExtension<PX.Objects.CR.BAccount>
{
#region UsrCustomField
[PXDBString(250, IsUnicode = true, BqlField =
typeof(BAccountR.acctName))]
[PXUIField(DisplayName = "Primary Vendor")]
public virtual string AcctName { get; set; }
public abstract class acctName : IBqlField
{
}
#endregion
}
As you found out the cache extension modifications applies to all screens who use that DAC. There is another extension mechanism applied on a per graph basis called CacheAttached that is applied after the cache extension.
To use it first you need to identify the graph of the screen you want to customize and the DAC field you want to modify. You can use the inspect element feature for this. In this example the graph for Customers screen is 'CustomerMaint' and the DAC field is 'Customer.acctName':
Once you have that information you can create an extension for that graph and extend the DAC field inside it. DAC field extensions defined in the graph using the CacheAttached method will only apply to screens who uses that graph:
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXUIField(DisplayName = "Display Name For Customers Graph")]
public virtual void Customer_AcctName_CacheAttached(PXCache sender)
{
}
}
The prototype convention for CacheAttached extensions is:
void DAC_DACField_CacheAttached(PXCache sender) { }
You change DAC and DACField to the field you are targeting. Method definition (body) should remain empty. The attributes decorating the CacheAttached method will apply to the field you're customizing. With attribute PXMerge you can tweak how the CacheAttached extension is applied, it allows to merge the field new attributes of the extension with the base one or completely replace the base attributes.
For more details look at this blog post:
http://asiablog.acumatica.com/2017/01/append-and-replace-of-dacs-attributes.html
you can also try like below but this is limited to the specific graph.
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
public override void Initialize()
{
PXUIFieldAttribute.SetDisplayName<Customer.acctName>(Base.BAccount.Cache, "Primary Vendor");
}
}

Adding Owner Name in the Purchase Order Lookup screen

I would like to add the Owner Name (on the PO Screen) in the Purchase Order>Order Nbr. field lookup screen. I tried to manually add the following in the Data Class for OrdNbr but it didn't bring the Employee name in the lookup screen. Can you please help or let me know if i am missing something.
Here is the full code i am trying(screenshot attached)
[PXCustomizeSelectorColumns(
typeof(PX.Objects.PO.POOrder.orderType),
typeof(PX.Objects.PO.POOrder.orderNbr),
typeof(PX.Objects.PO.POOrder.vendorRefNbr),
typeof(PX.Objects.PO.POOrder.orderDate),
typeof(PX.Objects.PO.POOrder.status),
typeof(PX.Objects.PO.POOrder.vendorID),
typeof(PX.Objects.PO.POOrder.vendorID_Vendor_acctName),
typeof(PX.Objects.PO.POOrder.vendorLocationID),
typeof(PX.Objects.PO.POOrder.curyID),
typeof(PX.Objects.PO.POOrder.curyOrderTotal),
typeof(PX.Objects.PO.POOrder.sOOrderType),
typeof(PX.Objects.PO.POOrder.sOOrderNbr),
typeof(PX.Objects.PO.POOrder.orderDesc),
typeof(PX.Objects.CR.CREmployee.acctCD),
typeof(PX.Objects.CR.CREmployee.bAccountID),
typeof(PX.Objects.CR.CREmployee.acctName))]
Many Thanksenter image description here
Since POOrder.employeeID has a PXSelector attribute on its definition:
And this Selector has a DescriptionField assigned:
On this case you can add Owner name by adding this line of code to your CacheExtension file(This will obtain that DescriptionField for the EmployeeID field):
public abstract class employeeID_CREmployee_acctName : PX.Data.IBqlField { }
See Snippet below:
namespace PX.Objects.PO
{
[PXNonInstantiatedExtension]
public class PO_POOrder_ExistingColumn : PXCacheExtension<PX.Objects.PO.POOrder>
{
#region OwnerName
public abstract class employeeID_CREmployee_acctName : PX.Data.IBqlField
{ }
#endregion
#region OrderNbr
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXCustomizeSelectorColumns(
typeof(PX.Objects.PO.POOrder.orderType),
typeof(PX.Objects.PO.POOrder.orderNbr),
typeof(PX.Objects.PO.POOrder.vendorRefNbr),
typeof(PX.Objects.PO.POOrder.orderDate),
typeof(PX.Objects.PO.POOrder.status),
typeof(PX.Objects.PO.POOrder.employeeID),
typeof(PX.Objects.PO.PO_POOrder_ExistingColumn.employeeID_CREmployee_acctName),
typeof(PX.Objects.PO.POOrder.vendorID),
typeof(PX.Objects.PO.POOrder.vendorID_Vendor_acctName),
typeof(PX.Objects.PO.POOrder.vendorLocationID),
typeof(PX.Objects.PO.POOrder.curyID),
typeof(PX.Objects.PO.POOrder.curyOrderTotal),
typeof(PX.Objects.PO.POOrder.sOOrderType),
typeof(PX.Objects.PO.POOrder.sOOrderNbr))]
public string OrderNbr { get; set; }
#endregion
}
}
Please notice that in case the POOrder.EmployeeID field would not have the "DescriptionField" set on the PXSelector Definition, you would have to modify the PXSelector of the OrderNbr to add a LeftJoin on the Desired Table(CREmployee on this case) so you could use the desired fields and add them to the PXCustomizeSelectorColumns attribute.

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

Resources