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;
}
}
Related
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 :
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.
Good day
I am trying to set my Input mask at runtime according to the country that is selected.
I created the following DAC to save the Input mask:
namespace PX.Objects.CS
{
public class CountryExt : PXCacheExtension<PX.Objects.CS.Country>
{
#region UsrPhoneMask
[PXDBString(50)]
[PXUIField(DisplayName="Phone Mask")]
public virtual string UsrPhoneMask { get; set; }
public abstract class usrPhoneMask : PX.Data.BQL.BqlString.Field<usrPhoneMask> { }
#endregion
}
}
The part I am struggling with is when I Override the attribute on-screen level, this is the Phone1 field on the Customer screen:
namespace PX.Objects.AR
{
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
#region Event Handlers
[PXDBString(50, IsUnicode = true,
InputMask = Search<CountryExt.usrPhoneMask, Where<Country.countryID,Equal<Current<Country.countryID>>>>]
[PXUIField(DisplayName = "Phone 1", Visibility = PXUIVisibility.SelectorVisible)]
// [PhoneValidation()]
[PXMassMergableField]
[PXPersonalDataField]
protected virtual void Contact_Phone1_CacheAttached(PXCache cache){ }
}
}
I know it is the search I am implementing wrong just don't know how to fix it.
I have also tried setting it using a const
public const string Masknum = PXSelect<CountryExt.usrPhoneMask, Where<Country.countryID, Equal<Current<Country.countryID>>>>;
public class masknum : PX.Data.BQL.BqlString.Constant<masknum>
{
public masknum() : base(Masknum) {; }
}
PXSelect<CountryExt.usrPhoneMask, Where<Country.countryID,Equal<Current<Country.countryID>>>>;
[PXDBString(50, IsUnicode = true, InputMask = Masknum)]
[PXUIField(DisplayName = "Phone 1", Visibility = PXUIVisibility.SelectorVisible)]
// If you do not remove below attribute the mask will not be set
// [PhoneValidation()]
// [PXMassMergableField]
[PXPersonalDataField]
protected virtual void Contact_Phone1_CacheAttached(PXCache cache)
{
}
Property values declared in DAC attribute are not dynamic because they are required to be constant values by .NET Framework compilers. To change the mask at runtime you should investigate the ReturnState property of CacheAttached and FieldSelecting events.
From the Source Code page (SM204570) you can search for the OrderSiteSelectorAttribute which implements a dynamic mask using these methods.
Other examples shipped in the product source code might be more useful for your use case so you can also do a broad search for ReturnState. Here's the relevant code shown in the screenshot above:
public override void CacheAttached(PXCache sender)
{
base.CacheAttached(sender);
PXDimensionAttribute attr = new PXDimensionAttribute(SiteAttribute.DimensionName);
attr.CacheAttached(sender);
attr.FieldName = _FieldName;
PXFieldSelectingEventArgs e = new PXFieldSelectingEventArgs(null, null, true, false);
attr.FieldSelecting(sender, e);
_InputMask = ((PXSegmentedState)e.ReturnState).InputMask;
}
public override void SubstituteKeyFieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
{
base.SubstituteKeyFieldSelecting(sender, e);
if (_AttributeLevel == PXAttributeLevel.Item || e.IsAltered)
{
e.ReturnState = PXStringState.CreateInstance(e.ReturnState, null, null, null, null, null, _InputMask, null, null, null, null);
}
}
EDIT:
From the matching DAC RowSelected event, try calling the SetInputMask method.
If that is producing the expected results it is the most straightforward way to achieve dynamic input mask:
PXStringAttribute.SetInputMask<DAC.field>(sender, inputMaskValue);
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 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.