Can I alias a field in a PXSelector - acumatica

I have a selector defined as follows:
[PXSelector(typeof(Search2<xTACTaxDocument.iD,
InnerJoin<xTACEntityMappingEIN,
On<xTACTaxDocument.clientEINID, Equal<xTACEntityMappingEIN.iD>>,
InnerJoin<xTACEntityMappingEIN1,
On<xTACTaxDocument.investmentEINID, Equal<xTACEntityMappingEIN1.iD>>>>>),
typeof(xTACTaxDocument.iD),
typeof(xTACTaxDocument.formID),
typeof(xTACTaxDocument.year),
typeof(xTACEntityMappingEIN.eIN),
typeof(xTACEntityMappingEIN1.eIN))]
Where I define an alias DAC as follows(redefining the fields I need to use) :
[Serializable]
public class xTACEntityMappingEIN1 : xTACEntityMappingEIN
{
public abstract new class iD : IBqlField { }
public abstract new class eIN : IBqlField { }
}
My question is - since the original ein and aliased DAC ein fields have the same name - is it possible - purely in the displayed grid - to rename the second one? Or, ideally, rename both of them? Didn't see that as an option anywhere in the intellisense...
This is kind of what I'm looking to do (see the aliased fields):
select xTACTaxDocument.iD
,xTACTaxDocument.FormID
,xTACTaxDocument.Year
,xTACEntityMappingEIN.EIN as 'ClientEIN'
,xTACEntityMappingEIN1.EIN as 'InvestmentEIN'
from xTACTaxDocument
Inner Join xTACEntityMappingEIN
On xTACTaxDocument.clientEINID = xTACEntityMappingEIN.iD
Inner Join xTACEntityMappingEIN xTACEntityMappingEIN1
On xTACTaxDocument.investmentEINID = xTACEntityMappingEIN1.iD

The only option would be to additionally override the EIN property in the xTACEntityMappingEIN1 DAC to use a different DisplayName in PXUIFieldAttribute:
[Serializable]
public class xTACEntityMappingEIN1 : xTACEntityMappingEIN
{
public abstract new class iD : IBqlField { }
public abstract new class eIN : IBqlField { }
[PXDBString(50, IsUnicode = true, IsKey = true)]
[PXUIField(DisplayName = "Investment EIN")]
public override string EIN { get; set; }
}
Please note, in the code snippet above I randomly chose string type for the EIN field. Ideally EIN field attributes should be close to identical in both xTACEntityMappingEIN and xTACEntityMappingEIN1, except the DisplayName property value for PXUIFieldAttribute.

The DAC Names need to be unique to "alias" a table. You cannot set an alias like you might use in SQL, but you can declare a new class inheriting the source class to give it a new "name" for the query. I had a similar Q&A here: Acumatica BQL Query with the same table more than once
In the inherited class you can change the display name of the fields as needed to "alias" a field name that repeats.
Here is a quick untested sample:
[Serializable]
public class xTACEntityMappingEINClient : xTACEntityMappingEIN
{
//Override field to set display name = "ClientEIN"
//[PXUIField(DisplayName = "ClientEIN")]
}
[Serializable]
public class xTACEntityMappingEINInvestment : xTACEntityMappingEIN
{
//Override field to set display name = "InvestmentEIN"
//[PXUIField(DisplayName = "InvestmentEIN")]
}
[PXSelector(typeof(Search2<xTACTaxDocument.iD,
InnerJoin<xTACEntityMappingEINClient,
On<xTACTaxDocument.clientEINID, Equal<xTACEntityMappingEINClient.iD>>,
InnerJoin<xTACEntityMappingEINInvestment ,
On<xTACTaxDocument.investmentEINID, Equal<xTACEntityMappingEINInvestment.iD>>>>>),
typeof(xTACTaxDocument.iD),
typeof(xTACTaxDocument.formID),
typeof(xTACTaxDocument.year),
typeof(xTACEntityMappingEINClient.eIN),
typeof(xTACEntityMappingEINInvestment .eIN))]

Related

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

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

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") { }
}
}

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.

BQL query not giving the results I expect

I have a BQL resultset consisting of several left joins, and one of the tables (ARCstRptControl) is joined multiple times under an 'alias' by way of inheriting the original DAC The code is shown below:
public class ARInv : PXGraph<ARInv, ARInvoice>
{
[Serializable]
public class ARCstRptControl1 : ARCstRptControl { }
[Serializable]
public class ARCstRptControl2 : ARCstRptControl { }
foreach (PXResult<ARTran
,PMTran
,ARCstRptControl
,ARCstRptControl1
,PMTask
,Account
,ARCstRptControl2> thistran in PXSelectJoin<ARTran,
LeftJoin<PMTran,
On<ARTran.pMTranID, Equal<PMTran.tranID>>,
LeftJoin<ARCstRptControl,
On<PMTran.origAccountGroupID, Equal<ARCstRptControl.accountID>>,
LeftJoin<ARCstRptControl1,
On<PMTran.accountGroupID, Equal<ARCstRptControl1.accountID>>,
LeftJoin<PMTask,
On<PMTask.projectID, Equal<PMTran.projectID>,
And<PMTask.taskID,Equal<PMTran.taskID>>>,
LeftJoin<Account,
On<ARTran.accountID, Equal<Account.accountID>>,
LeftJoin<ARCstRptControl2,
On<Account.accountGroupID, Equal<ARCstRptControl2.accountID>>>>>>>>,
Where<ARTran.tranType, Equal<Current<ARInvoice.docType>>,
And<ARTran.refNbr, Equal<Current<ARInvoice.refNbr>>>>>.Select(this))
{
ARTran artran = (ARTran)thistran;
PMTran pmtran = (PMTran)thistran;
ARCstRptControl srcgrp = (ARCstRptControl)thistran;
ARCstRptControl1 destgrp = (ARCstRptControl1)thistran;
PMTask pmtask = (PMTask)thistran;
Account account = (Account)thistran;
ARCstRptControl2 destgrp2 = (ARCstRptControl2)thistran;
All the table / DAC variables have the expected results, except ARCstRptControl2. I've moved this entire query into SQL Server and it gives me the results I want, including ARCstRptControl2 - but I must be doing something wrong with the join here in the BQL. Any ideas?
Since I'm using aliased DACs (ARCstRptControl1 and 2), and since I'm using two fields from those aliased DACs, I needed to have those fields (and any others that would be used) from that alias declared in the DAC declaration, as follows (i.e., I'm using accountID and columnID in the join):
[Serializable]
public class ARCstRptControl1 : ARCstRptControl
{
public abstract new class accountID : IBqlField { }
public abstract new class columnID : IBqlField { }
}

Resources