Acumatica - Need underscores in my email addresses - acumatica

I have a field in my customization that I've set to [PXDBEmail] Unfortunately, this field replaces entered underscores with a space. Is there a way to keep it from doing so?
Update - DAC code below
public abstract class customerID : PX.Data.IBqlField
{
}
protected string _CustomerID;
[PXDBEmail]
[PXUIField(DisplayName = "User Name")]
public virtual string CustomerID
{
get
{
return this._CustomerID;
}
set
{
this._CustomerID = value != null ? value.Trim() :null;
}
}

Out of the box, the Email field on the Customers screen accept undercores without any issues:
Could you please compare the decalration of your custom field with the declaration of the EMail field from the Contact DAC?
public partial class Contact : IBqlTable, IContactBase, IAssign, IPXSelectable, CRDefaultMailToAttribute.IEmailMessageTarget
{
...
#region EMail
public abstract class eMail : PX.Data.IBqlField { }
private string _eMail;
[PXDBEmail]
[PXUIField(DisplayName = "Email", Visibility = PXUIVisibility.SelectorVisible)]
[PXMassMergableField]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
public virtual String EMail
{
get { return _eMail; }
set { _eMail = value != null ? value.Trim() : null; }
}
#endregion
...
}

Turns out my ASPX had a PXMaskEdit field instead of a PXTextEdit Field. Strange one!
Thanks for all the input.

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 :

How can I get a wildcard appended to a substring of a DAC field?

The screen I'm customizing is the 'Requests' screen (RQ301000) - and I want to modify the Vendor lookup in the grid to be based on the Request class chosen in the header. I already know how to modify the Vendor selector to include a filter, as I have done this on the Requisitions screen - but that customization included adding a user field for Request Class (which doesn't exist on the Requisitions screen).
I do have code that I obtained previously that gets a wildcard appended value of a field. The problem is, this code used a User field that was in the same DAC as the wildcard field - The code is shown below:
public class RQRequisitionExt : PXCacheExtension<RQRequisition>
{
#region UsrRequestClass
[PXDBString(10, IsUnicode = true)]
[PXUIField(DisplayName = "NSA Request Class", Visibility = PXUIVisibility.SelectorVisible)]
[PXSelector(typeof(RQRequestClass.reqClassID), DescriptionField = typeof(RQRequestClass.descr))]
public virtual string UsrRequestClass { get; set; }
public abstract class usrRequestClass : IBqlField {}
#endregion
//This is a DAC field that creates / tacks on a wildcard to the end of the UsrRequestClass field above...
public abstract class myFieldWildcard : IBqlField { };
[PXString(30, IsUnicode = true)]
public virtual string MyFieldWildcard
{
[PXDependsOnFields(typeof(usrRequestClass))]
get
{
//return PXDatabase.Provider.SqlDialect.WildcardAnything + UsrRequestClass + PXDatabase.Provider.SqlDialect.WildcardAnything;
if (UsrRequestClass != null)
return PXDatabase.Provider.SqlDialect.WildcardAnything + UsrRequestClass.Substring(0, 2) + PXDatabase.Provider.SqlDialect.WildcardAnything;
else
return UsrRequestClass;
}
}
}
For what I'm trying to do on the Requests screen, I'm not using a user field for this - I'm using the Request Class field already on the screen - but I have no idea how to get the value of this field to use in the wildcard 'get' routine.
Essentially, I want to obtain the Request Class value on the screen and use it in this wildcard field to return to my modified Vendor selector (not shown - but done using a CacheAttached event).
Any help would be appreciated. Thanks.
The solution, for me, was to redefine the Request Class field in the same DAC extension that contained the wildcard field, as follows:
public class RQRequestExt : PXCacheExtension<RQRequest>
{
//Redefine the Request Class in this DAC extension
#region ReqClassID
public abstract class reqClassID : IBqlField {}
[PXDBString(10, IsUnicode = true)]
[PXDefault(typeof(RQSetup.defaultReqClassID))]
[PXUIField(DisplayName = "Request Class", Visibility = PXUIVisibility.SelectorVisible)]
[PXSelector(typeof(RQRequestClass.reqClassID), DescriptionField = typeof(RQRequestClass.descr))]
public virtual string ReqClassID { get; set; }
#endregion
//This is a DAC field that creates / tacks on a wildcard to the end of the UsrRequestClass field above...
public abstract class rQRequestwildcard : IBqlField { };
[PXString(30, IsUnicode = true)]
public virtual string RQRequestwildcard
{
[PXDependsOnFields(typeof(RQRequest.reqClassID))]
get
{
if (ReqClassID != null)
return PXDatabase.Provider.SqlDialect.WildcardAnything + ReqClassID.Substring(0, 2) + PXDatabase.Provider.SqlDialect.WildcardAnything;
else
return PXDatabase.Provider.SqlDialect.WildcardAnything;
}
}
}
This way I have a reference to the Request Class ID used in the Wildcard field operation...

PMTimeActivity Usr Fields

I'm lost and not sure I am going about this the right way.
I have placed a PXAction Button on the EP305000 screen.
EP305000 Screen
When the button is pressed I wanted to search for any records in the PMTimeActivity table for the current user that has the UsrPIXIClockIn NOT null AND the UsrPIXIClockOut Null.
If found, need to set its value to the current time. If not found then create a new record with the UsrPIXIClockIn field set to the current time.
However, my first attempt of just trying to read the Usr fields is creating an error. When I try to parse a PXResultSet, code lines containing my Usr Fields are throwing an error when compiling.
There error is: 'PX.Objects.CR.PMTimeActivity' does not contain a definition for 'UsrPIXIClockIn' and no extension method 'UsrPIXIClockIn' accepting a first argument of type 'PX.Objects.CR.PMTimeActivity'
I am not sure where this definition belongs or how to define it. Here is the Code I have:
[Serializable]
public class PMTimeActivityExt : PXCacheExtension<PMTimeActivity>
{
public PXSelect<PMTimeActivity> PMTimeActivity;
#region UsrPIXIClockIn
[PXDBTime(DisplayMask = "t", UseTimeZone = false)]
[PXUIField (DisplayName="Clock In")]
public virtual DateTime? UsrPIXIClockIn { get; set; }
public abstract class usrPIXIClockIn : IBqlField { }
#endregion
#region UsrPIXIClockOut
[PXDBTime(DisplayMask = "t", UseTimeZone = false)]
[PXUIField (DisplayName="Clock Out")]
public virtual DateTime? UsrPIXIClockOut { get; set; }
public abstract class usrPIXIClockOut : IBqlField { }
#endregion
#region UsrPIXITotalHours
[PXDBDecimal]
[PXUIField (DisplayName="Total Hours")]
public virtual decimal? UsrPIXITotalHours { get; set; }
public abstract class usrPIXITotalHours : IBqlField { }
#endregion
}
public class TimeCardMaint_Extension : PXGraphExtension<TimeCardMaint>
{
public PXSelect<PMTimeActivity> PMTimeActivity;
public PXAction<EPTimeCard> PunchCard;
public PXAction<PX.Objects.EP.EPTimeCard> PunchTimeCard;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Punch Time Card")]
protected void punchTimeCard(PXCache cache)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.AppendLine("Started...\n");
EPEmployee employeeByUserID = PXSelect<EPEmployee, Where<EPEmployee.bAccountID, Equal<Current<EPTimeCard.employeeID>>>>.Select(this.Base);
Guid userID = (Guid) employeeByUserID.UserID;
sb.AppendLine("user ID:" + userID.ToString() + "\n");
// This one returns all records.
PXResultset<PMTimeActivity> TimeActivity = PXSelect<PMTimeActivity>.Select(this.Base);
foreach (PMTimeActivity timeRecord in TimeActivity)
{
if (timeRecord.OwnerID == userID) {
sb.AppendLine("UsrPIXIClockIn:" + timeRecord.UsrPIXIClockIn + "\n");
}
}
sb.AppendLine("\nEnded...\n");
throw new PXException("Clicked Punch Time Card!\n" + sb.ToString());
}
}
As for the PXSelect for the PXResultSet I tried this:
PXResultset<PMTimeActivity> TimeActivity = PXSelect<PMTimeActivity, Where<Required<PMTimeActivity.ownerID>, Equal<Current<PMTimeActivity.ownerID>>>>.Select(this.Base, userID);
But no records are ever found. What am I doing wrong?
The error message boils down to: PMTimeActivity does not contain UsrPIXIClockIn.
PMTimeActivity is the base DAC and the user fields are in the extended DAC PMTimeActivityExt.
You need to fetch the extension from the base DAC first using GetExtension method and access your user field on the extension record timeRecordExt.UsrPIXIClockIn:
foreach (PMTimeActivity timeRecord in TimeActivity)
{
PMTimeActivityExt timeRecordExt = timeRecord.GetExtension<PMTimeActivityExt>();
if (timeRecordExt != null && timeRecord.OwnerID == userID) {
sb.AppendLine("UsrPIXIClockIn:" + timeRecordExt.UsrPIXIClockIn + "\n");
}
}
In your question I see there's a data view declaration in the DAC extension. Maybe that's a typo, you should remove it as DAC extension should only contain user fields. This is important because Acumatica aggressively parses these code structures. So remove that line from PMTimeActivityExt class:
public PXSelect<PMTimeActivity> PMTimeActivity;

Change label name of default fields

I want to show which user created Invoice, for this i have added default Acumatica field, but the label is showing as Created By, how can i change that label name to "Invoice Created By". Please have a look at below screenshot for field am referring to.
You could use PXUIFieldAttribute.SetDisplayName static method to change DAC field’s display name. This change will be applicable only for Sales Invoice Entry Graph (SO303000 screen)
public class SOInvoiceEntryPXDemoExt : PXGraphExtension<SOInvoiceEntry>
{
public override void Initialize()
{
PXUIFieldAttribute.SetDisplayName<ARInvoice.createdByID>(Base.Document.Cache, "Invoice Created By");
}
}
If you need display name changed for this field in all screens, you need to have DAC Extension as below:
With this, attributes specified in an extension DAC apply to DAC class in every Graph of the application unless a Graph replaces them with other attributes.
public class ARInvoicePXDemoExt : PXCacheExtension<ARInvoice>
{
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXUIField(DisplayName = "Invoice Created By", Enabled = false, IsReadOnly = true)]
public virtual Guid? CreatedByID { get; set; }
}
You need to add CreatedByID field on screen SO303000
And set DisplayMode property to Text.
The 'CreatedByID' I believe is an audit field and therefore cannot easily change the ui of the additional data fields available through the control. The resolution I would suggest is a non database backed UI field that is populated during row selecting. Example can be found below :
public class SOOrderEntryExtension : PXGraphExtension<SOOrderEntry>
{
public virtual void SOOrder_RowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
SOOrder row = e.Row as SOOrder;
if(row != null)
{
SOOrderExtension rowExt = PXCache<SOOrder>.GetExtension<SOOrderExtension>(row);
Users user = PXSelectReadonly<Users, Where<Users.pKID, Equal<Required<Users.pKID>>>>.Select(this.Base, row.CreatedByID);
if(user != null)
{
rowExt.InvoiceCreatedBy = user.DisplayName;
}
}
}
}
public class SOOrderExtension : PXCacheExtension<SOOrder>
{
public abstract class invoiceCreatedBy : PX.Data.IBqlField
{
}
[PXString]
[PXUIField(DisplayName = "Invoice Created By")]
public virtual string InvoiceCreatedBy { get; set; }
}

Populating unbound column with fix value reference to other table

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;
}
}

Resources