Need help in selector control - acumatica

I created a selector control which displays a list of all serial #s from INItemLotSerial table, it works fine, the problem is the description field is showing InventoryID, how to show InventoryCD. Please have a look at below sample code.
[PXSelector(typeof(Search<INItemLotSerial.lotSerialNbr>),
new Type[] { typeof(INItemLotSerial.lotSerialNbr), typeof(INItemLotSerial.inventoryID) },
SubstituteKey = typeof(INItemLotSerial.lotSerialNbr), DescriptionField = typeof(INItemLotSerial.inventoryID))]
// i also joined with InventoryItem but this doesn't works.
[PXSelector(typeof(Search2<INItemLotSerial.lotSerialNbr,
LeftJoinSingleTable<InventoryItem, On<InventoryItem.inventoryID,Equal<INItemLotSerial.inventoryID>>>>),
new Type[] { typeof(INItemLotSerial.lotSerialNbr), typeof(INItemLotSerial.inventoryID) },
SubstituteKey = typeof(INItemLotSerial.lotSerialNbr), DescriptionField = typeof(InventoryItem.inventoryCD))]

The main problem with DescriptionField property is that it is waiting for getting the field from the same table for which Selector is written. But in the case of ID/CD usually, the CD is not present in the table where ID is present, except the main table.
UPDATED I have removed previous code (implementation using custom attributes and FieldSelecting event handler) because of the performance issues which it is bringing with it. The code below is resulting with the same lookup but getting the data with one inner join instead of all the requests which the previous code was doing.
You can do the following to get this lookup with description:
Create a PXProjection on INItemLotSerial and InventoryItem tables like below:
[PXCacheName("Lot Serials with Inventory CD")]
[PXProjection(typeof(Select2<INItemLotSerial,
InnerJoin<InventoryItem,
On<INItemLotSerial.inventoryID, Equal<InventoryItem.inventoryID>>>>))]
public class INItemLotSerialWithInventoryItem : IBqlTable
{
[PXDBInt(BqlField = typeof(INItemLotSerial.inventoryID))]
[PXUIField(DisplayName = "Inventory ID", Visibility = PXUIVisibility.Visible, Visible = false)]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : IBqlField { }
[PXDBString(InputMask = "", IsUnicode = true, BqlField = typeof(InventoryItem.inventoryCD))]
[PXUIField(DisplayName = "Inventory ID")]
public virtual string InventoryCD { get; set; }
public abstract class inventoryCD : IBqlField { }
[PXDBString(InputMask = "", IsUnicode = true, BqlField = typeof(INItemLotSerial.lotSerialNbr))]
[PXUIField(DisplayName = "Lot/Serial Nbr")]
public virtual string LotSerialNbr { get; set; }
public abstract class lotSerialNbr : IBqlField { }
}
Set your selector to use this PXProjection like below:
[PXSelector(typeof(Search<INItemLotSerialWithInventoryItem.lotSerialNbr>),
new Type[] { typeof(INItemLotSerialWithInventoryItem.lotSerialNbr) },
SubstituteKey = typeof(INItemLotSerialWithInventoryItem.lotSerialNbr),
DescriptionField = typeof(INItemLotSerialWithInventoryItem.inventoryCD))]
As a result, you will get lookup like below:

Related

Adding Customer Class to GLTran \ GLTranR to see in screen GL404000 (Account Details)

I am currently trying to add the customer account class to the viewing area of the GL404000 screen with the by extending the GLTran DAC.
The AccountID, AccountCD and Account name are already available so I thought it would be an easy task.
In GLTranR, I saw where they were pulling in the account data:
public new abstract class referenceID : PX.Data.BQL.BqlInt.Field<referenceID> { }
[PXDBInt()]
[PXDimensionSelector("BIZACCT", typeof(Search<BAccountR.bAccountID>), typeof(BAccountR.acctCD), DescriptionField = typeof(BAccountR.acctName), DirtyRead = true)]
[PXUIField(DisplayName = CR.Messages.BAccountCD, Enabled = false, Visible = false)]
public override Int32? ReferenceID
{
get
{
return this._ReferenceID;
}
set
{
this._ReferenceID = value;
}
}
The line that I attempted to change to my need was the [PXDimensionSelector()] however I cannot get this to pull in the class data. Even when I dont change the code at all it will not populate the column.
public new abstract class usrBusinessAccountClass : PX.Data.BQL.BqlInt.Field<usrBusinessAccountClass> { }
protected Int32? _UsrBusinessAccountClass;
[PXDBInt()]
[PXDimensionSelector("BIZACCT", typeof(Search<BAccountR.bAccountID>), typeof(BAccountR.acctCD), DescriptionField = typeof(BAccountR.acctClass), DirtyRead = true)]
[PXUIField(DisplayName = "Business Account Class", Enabled = false, Visible = false)]
public virtual Int32? UsrBusinessAccountClass
{
get {return _UsrBusinessAccountClass;}
set{ _UsrBusinessAccountClass = value;} // set does work but value does not???
}
just for a test I changed the setter to:
set { _UsrBusinessAccountClass = 1234; }
And that populated the column with the value 1234, so that is why I think my issue is just with selecting the class.
I would show this but I need 10 rep to post images.
You are on the proper track. The following code shows how to retrieve additional data to display within the screen.
Non-Database backed field on the DAC you wish to display data on :
public sealed class GLTranRExtension : PXCacheExtension<GLTranR>
{
public abstract class usrClassID : BqlString.Field<usrClassID>
{
}
[PXString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
[PXSelector(typeof(CRCustomerClass.cRCustomerClassID), DescriptionField = typeof(CRCustomerClass.description))]
[PXUIField(DisplayName = "Business Account Class")]
public string UsrClassID { get; set; }
}
Graph extension in which the extension field is then populated with data :
public class AccountByPeriodEnqExtension : PXGraphExtension<AccountByPeriodEnq>
{
protected virtual void __(Events.RowSelecting<GLTranR> e)
{
if(e.Row is GLTranR row)
{
GLTranRExtension rowExt = row.GetExtension<GLTranRExtension>();
using(new PXConnectionScope())
{
BAccount bAccount = PXSelectReadonly<BAccount, Where<BAccount.bAccountID, Equal<Required<BAccount.bAccountID>>>>.Select(this.Base, row.ReferenceID);
if(bAccount != null)
{
rowExt.UsrClassID = bAccount.ClassID;
}
}
}
}
}
You will also need to add within the GL404000 the UI elements for your new extension fields. The result will look as follows :

Enabling "AllowAddNew" and/or "AllowEdit" on selector for custom DAC

I have created a custom DAC, Graph, and Screen to manage tracking of new entity for client, called "Management Company." New screen is simple Grid with CRUD controls. Selector on Customer screen allows me to choose from list of "Management Company" entries. I also added new field to Contact DAC and DB table to track which "Management Company" is assigned to a given contact. This field is where the selector is configured.
I am trying to enable the "AllowAddNew" and/or "AllowEdit" properties of this selector. When I set to "True," the buttons show up but they don't do anything.
I can create and save new entries to this DB table via the new screen and I can retrieve them with the Selector just fine. I just can't create new from selector.
I have tried looking this up and I'm not finding much information.
How can I achieve this?
Sample of DAC:
namespace PX.Objects.CR
{
[Serializable]
public class UsrCustomerManagementCompany : IBqlTable
{
#region MancompID
[PXDBString(16, IsUnicode = true, InputMask = ">LLLLLLLLLLLLLLLL", IsKey = true)]
[PXUIField(DisplayName = "Company ID")]
[PXDefault]
public virtual string MancompID { get; set; }
public abstract class mancompID : IBqlField { }
#endregion
#region MancompName
[PXDBString(60, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Company Name")]
[PXDefault]
public virtual string MancompName { get; set; }
public abstract class mancompName : IBqlField { }
#endregion
#region MancompDescr
[PXDBString(4000, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Description")]
public virtual string MancompDescr { get; set; }
public abstract class mancompDescr : IBqlField { }
#endregion
}
}
Graph:
using System;
using PX.Data;
using PX.Objects.CR;
namespace ClientCode
{
public class ManagementCompanyMaint : PXGraph<ManagementCompanyMaint, UsrCustomerManagementCompany>
{
public PXSelect<UsrCustomerManagementCompany> ManagementCompanies;
}
}
Contact DAC Extension and Selector:
namespace PX.Objects.CR
{
public class ContactExt : PXCacheExtension<PX.Objects.CR.Contact>
{
#region UsrManagementCompany
[PXDBString]
[PXUIField(DisplayName = "Management Company")]
[PXSelector(
typeof(Search<UsrCustomerManagementCompany.mancompID>),
new Type[]
{
typeof(UsrCustomerManagementCompany.mancompID),
typeof(UsrCustomerManagementCompany.mancompName)
},
SubstituteKey = typeof(UsrCustomerManagementCompany.mancompName)
)]
public virtual string UsrManagementCompany { get; set; }
public abstract class usrManagementCompany : IBqlField { }
#endregion
}
}
I think all you are missing is the PXPrimaryGraph attribute on your DAC to indicate for that record type what is the main graph to refer to.
In your case try adding...
[PXPrimaryGraph(typeof(ClientCode.ManagementCompanyMaint))]
[Serializable]
public class UsrCustomerManagementCompany : IBqlTable
{
//...
}
Here are some related questions that might also help:
How to create a hyperlink user field
how to use AllowEdit in Acumatica

Acumatica - Possible to create several numberingId with existing numberingId

i have some problems with AutoNumberAttribute in Acumatica. In my Project Issue screen i can create new entity with existing numberingId (see screenshot below)
Field selector with AutoNumberAttribute
But other entities like POOrder, Case haven't this promlems. Code for this shown below:
[Serializable]
[PXEMailSource]
[PXPrimaryGraph(typeof(ProjectIssueMaint))]
[PXCacheName(Messages.ProjectIssue.CacheName)]
public class ProjectIssue : BaseCache, IBqlTable, IAssign, IPXSelectable
{
[PXDBIdentity]
[PXUIField(Visible = false, Visibility = PXUIVisibility.Invisible, DisplayName = Messages.ProjectIssue.NumberId)]
public virtual int? ProjectIssueId
{
get;
set;
}
[PXDefault]
[PXFieldDescription]
[PXDBString(10, IsKey = true, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = Messages.ProjectIssue.NumberId, Required = true)]
[PXSelector(typeof(Search<projectIssueCd>),
typeof(projectIssueCd),
typeof(projectId),
typeof(projectTaskId),
typeof(classId),
typeof(summary),
typeof(status),
typeof(ownerID),
Filterable = true)]
[AutoNumber(typeof(ProjectManagementSetup.projectIssueNumberingId), typeof(createdDateTime))]
public virtual string ProjectIssueCd
{
get;
set;
}
public abstract class projectIssueCd : IBqlField
{
}
public abstract class projectIssueId : IBqlField
{
}
}
[Serializable]
[PXCacheName(Messages.ProjectManagementSetup.CacheName)]
public class ProjectManagementSetup : BaseCache, IBqlTable
{
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
[PXDefault(Constants.ProjectIssue.NumberingId)]
[PXSelector(typeof(Numbering.numberingID), DescriptionField = typeof(Numbering.descr))]
[PXUIField(DisplayName = Messages.ProjectManagementSetup.ProjectIssueNumberingSequence)]
public virtual string ProjectIssueNumberingId
{
get;
set;
}
public abstract class projectIssueNumberingId : IBqlField
{
}
}
public class ProjectIssueMaint : PXGraph<ProjectIssueMaint, ProjectIssue>
{
[PXViewName(Messages.ProjectIssue.CacheName)]
[PXCopyPasteHiddenFields(typeof(ProjectIssue.status))]
public PXSelect<ProjectIssue> ProjectIssue;
[PXHidden]
[PXCheckCurrent]
public PXSetup<ProjectManagementSetup> ProjectManagementSetup;}
public class ProjectManagementSetupMaint : PXGraph<ProjectManagementSetupMaint>
{
public PXSave<ProjectManagementSetup> Save;
public PXCancel<ProjectManagementSetup> Cancel;
public PXSelect<ProjectManagementSetup> ProjectManagementSetup;
}
I reproproduce this issue by change the last number field in the numbering sequence screen (see screenshot https://snag.gy/UpIe8a.jpg).
So somebody know why this maybe happend? Any information will help me)
The AutoNumberAttribute completely relies on the configuration of the associated Numbering Sequence and does not have built-in validation to prevent insertion of the record with the duplicated number, which was generated by the AutoNumberAttribute. Since your table is built with A Pair of Columns with Key Substitution in the UI, you must add a unique index consisting of the CompanyID and ProjectIssueCd columns to prevent the insertion of multiple ProjectIssue records with the same ProjectIssueCd on the database level.
CREATE UNIQUE NONCLUSTERED INDEX [ProjectIssue_ProjectIssueCd_Uindex] ON [dbo].[ProjectIssue]
(
[CompanyID] ASC,
[ProjectIssueCd] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)

Customizing Selector when another another Selector value changes

I need to Customize CaseClassID Selector on Cases Screen. It should refresh with different values when Contract field is selected on the CaseScreen under the Additional Info tab. Right now the CaseClass is displaying values from CRCase table.But, now if the contract changes the fieldupdatedEvent should be triggered and CaseClassID selector should have values accordingly. Please suggest me how to customize the CaseClassID selector inside FieldUpdated Event Handler
protected virtual void CRCase_ContractID_FieldUpdated(PXCache sender,
PXFieldUpdatedEventArgs e)
{
CRCase cc = (CRCase)e.Row;
if (cc == null) return;
CRCase_CaseClassID_CacheAttached(sender);
}
[PXMergeAttributes(Method = MergeMethod.Replace)]
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
[PXDefault(typeof(Search<CRSetup.defaultCaseClassID>))]
[PXUIField(DisplayName = "Class ID")]
[PXSelector(typeof(Search2<CRCaseClass.caseClassID,
InnerJoin<CaseContract, On<CaseContract.caseClassID,
Equal<CRCaseClass.caseClassID>>,
InnerJoin<Contract, On<CaseContract.contractID,
Equal<Contract.templateID>>,
InnerJoin<CRCase, On<Contract.contractID,
Equal<Current<CRCase.contractID>>>>>>,
Where<CaseContract.active, Equal<True>>>),
DescriptionField = typeof(CRCaseClass.description),
CacheGlobal = true)]
[PXMassUpdatableField]
public virtual String CaseClassID { get; set; }
public virtual void CRCase_CaseClassID_CacheAttached(PXCache sender){
}
Override CaseClassID selector and add your custom logic in its type parameter.
You can create a custom unbound field to filter the selector according to your business logic. When you want to change selector filter, just change the custom field.
#region CaseClassID
public abstract class caseClassID : IBqlField { }
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
[PXDefault(typeof(Search<CRSetup.defaultCaseClassID>))]
[PXUIField(DisplayName = "Class ID")]
// Use your custom field (filterCaseClassID) in the selector type parameter
[PXSelector(typeof(Search<CRCaseClass.caseClassID,
Where<CRCaseClass.caseClassID, Equal<filterCaseClassID>>>),
DescriptionField = typeof(CRCaseClass.description),
CacheGlobal = true)]
[PXMassUpdatableField]
public virtual String CaseClassID { get; set; }
#endregion
#region FilterCaseClassID
public abstract class filterCaseClassID : IBqlField { }
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
// Change the value of your custom field to set the selector filter
public virtual String FilterCaseClassID { get; set; }
#endregion
EDIT overriding DAC field in graph extension and filtering Selector by using a field from another DAC:
using PX.Data;
using PX.Objects.CR.MassProcess;
using System;
namespace PX.Objects.CR
{
[Serializable]
public class CaseContract : IBqlTable
{
public abstract class caseClassID : IBqlField { }
[PXString(10, IsUnicode = true)]
[PXUIField(DisplayName = "Case Class ID")]
[PXSelector(typeof(CRCaseClass.caseClassID),
DescriptionField = typeof(CRCaseClass.description))]
public virtual String CaseClassID
{
get; set;
}
}
public class CRCaseMaint_Extension : PXGraphExtension<CRCaseMaint>
{
[PXMergeAttributes(Method = MergeMethod.Replace)]
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
[PXDefault(typeof(Search<CRSetup.defaultCaseClassID>))]
[PXUIField(DisplayName = "Class ID")]
[PXSelector(typeof(Search<CRCaseClass.caseClassID,
Where<Current<CaseContract.caseClassID>, IsNull,
Or<CRCaseClass.caseClassID, Equal<Current<CaseContract.caseClassID>>>>>),
DescriptionField = typeof(CRCaseClass.description),
CacheGlobal = true)]
[PXMassUpdatableField]
public virtual void CRCase_CaseClassID_CacheAttached(PXCache sender)
{
}
}
}

Search in GI Gives error while using Sector field

I have created a Name value pair field for Sales Order table and Search is giving error while using the field from Description field in selector
#region UsrLoader
public abstract class usrLoader : IBqlField { }
[PXDBString(128, IsUnicode = true)]
[PXUIField(DisplayName = "Operator 1")]
[PXSelector(typeof(EPEmployee.acctCD),
new Type[]
{
typeof(EPEmployee.acctCD),
typeof(EPEmployee.acctName)
},
DescriptionField = typeof(EPEmployee.acctName))]
public virtual string UsrLoader { get; set; }
#endregion
#region UsrUnLoader
[PXDBString(128)]
[PXUIField(DisplayName = "Operator 2")]
[PXSelector(typeof(EPEmployee.acctCD),
new Type[]
{
typeof(EPEmployee.acctCD),
typeof(EPEmployee.acctName)
},
DescriptionField = typeof(EPEmployee.acctName))]
public virtual string UsrUnLoader { get; set; }
public abstract class usrUnLoader : IBqlField { }
#endregion
I am getting the following error
Typically I see the Invalid column error when the customization hasn't been published to insert the field in the database table. Did you publish after adding the fields?
Also, the warnings might tell you to join in the parent table. Did you try doing a join to the EPEmployee table to use the description/name field in your GI?

Resources