Adding Custom Entity Type in CRM Activity for selecting in Relative Entity - acumatica

I have implemented CRM activity on the Custom page where the Key Field is SOOrder Type, SOOrder Nbr & Job Code which are stored in custom DAC. I have tried to add the Entity Type listed on Related Entity and I am not able to figure out how to do it. Pls let me know where to add or override the method to Implement the functionality
The following cod used to implement the CRM Activity
public sealed class SOOrderJobActivities : CRActivityList<PSSOOrderJob>
{
public SOOrderJobActivities(PXGraph graph)
: base(graph) { }
protected override RecipientList GetRecipientsFromContext(NotificationUtility utility, string type, object row, NotificationSource source)
{
var recipients = new RecipientList();
var order = _Graph.Caches[typeof(PSSOOrderJob)].Current as PSSOOrderJob;
if (order == null || source == null)
return null;
SOOrder ord = SOOrder.PK.Find(_Graph, order.OrderType, order.OrderNbr);
var contact = SOOrder.FK.Contact.FindParent(_Graph, ord);
if (contact == null || contact.EMail == null)
return null;
recipients.Add(new NotificationRecipient()
{
Active = true,
AddTo = RecipientAddToAttribute.To,
Email = contact.EMail
});
source.RecipientsBehavior = RecipientsBehaviorAttribute.Override;
return recipients;
}
}
Update
After going through the Acumatica code, I have done the following changes
#region Noteid
[PXNote(ShowInReferenceSelector =true,Selector =typeof(Search2<PSSOOrderJob.jobCode,
InnerJoin<SOOrder,On<PSSOOrderJob.orderType,Equal<SOOrder.orderType>,And<PSSOOrderJob.orderNbr, Equal<SOOrder.orderNbr>>>>,
Where<SOOrder.orderType,Equal<Current<PSSOOrderJob.orderType>>,And<SOOrder.orderNbr, Equal<Current<PSSOOrderJob.orderNbr>>>>>))]
public virtual Guid? Noteid { get; set; }
public abstract class noteid : PX.Data.BQL.BqlGuid.Field<noteid> { }
#endregion
The entity comes into selection, But I am not able to select the relative entity document and the value is not getting updated in the related entity field.
The above screenshot the select is missing and not able to select the document

The following steps I have done to add relative Entity for any Activity using custom DAC
1. Added ShowInReferenceSelector = true in PXNoteID field.
2. Added Selector in PXNoteID field
3. Decorated [PX.Data.EP.PXFieldDescription] attribute for Key fields
#region NoteID
[PXNote(ShowInReferenceSelector = true, Selector = typeof(Search2<PSSOOrderJob.jobCode,
InnerJoin<SOOrder, On<PSSOOrderJob.orderType, Equal<SOOrder.orderType>, And<PSSOOrderJob.orderNbr, Equal<SOOrder.orderNbr>>>>,
Where<SOOrder.orderType, Equal<Current<PSSOOrderJob.orderType>>, And<SOOrder.orderNbr, Equal<Current<PSSOOrderJob.orderNbr>>,And<PSSOOrderJob.jobType,Equal<Current<PSSOOrderJob.jobType>>>>>>), DescriptionField = typeof(PSSOOrderJob.jobCode))]
//[PXNote(ShowInReferenceSelector = true)]
public virtual Guid? NoteID { get; set; }
public abstract class noteID : PX.Data.BQL.BqlGuid.Field<noteID> { }
#endregion
#region JobCode
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = "Job Code")]
[PXDefault()]
[PXSelector(typeof(Search<PSSOOrderJob.jobCode, Where<PSSOOrderJob.orderType, Equal<Current<PSSOOrderJob.orderType>>, And<PSSOOrderJob.orderNbr, Equal<Current<PSSOOrderJob.orderNbr>>,And<PSSOOrderJob.jobType, Equal<Current<PSSOOrderJob.jobType>>>>>>), typeof(PSSOOrderJob.jobCode), ValidateValue = false)]
[PSSOOrderJobNbr.Numbering()]
[PX.Data.EP.PXFieldDescription]
public virtual string JobCode { get; set; }
public abstract class jobCode : PX.Data.BQL.BqlString.Field<jobCode> { }
#endregion
This automatically fills the related entity field with Jobcode.
There still one issue I am facing is not able to access the selector due to Entity field width is more than the popup window and I do not know how to fix it.

This answer is to address the popup size only.
First, give browser zoom a try 'control' + 'minus' key. It might work as a quick workaround.
Otherwise, use the browser debugger feature. Open it with F12 key. Then use the browser debugger inspect element feature (1). Click on the smart panel (2). Go up a bit in html control hierarchy until you reach and select the smart panel root which is a table element (3). Change the width of the smart panel popup using the debugger CSS properties editor (4).
If selector control size increases automatically with window size; change the selector control width instead of popup width using browser debugger CSS property editor.

Related

Child DAC are not inserting when add a new Item

I have 2 scenarios, I am facing issue.
I have 3 DAC, One is Parent and other 2 are child DAC.
I have tab view, and showing data accordingly.
First tab showing Parent DAC data.
Second and third are showing child DAC data.
I am creating new item, Now i press Add(+) button and fill, Information in Parent tab, but not filled any data in 2nd and 3rd tab, when i press SAVE then only parent DAC saved, 2nd and 3rd tab rows not created in database, I want to save 2nd and 3rd Tab DAC also, what should i do?
Another case:
i am not allowing DAC to update, I am setting DAC.Cahce.AllowUpdated = false; all controls are disabled excepting Checkbox, why?
Also when we are on 3rd tab and click on toolbar Navigation button, then 1st tab data doesn't refresh, it is showing previous selected item data. How to fix this issue?
We are not using PXGrid for any child data, there is one to one relation ship between all 3 DAC.
/// Parent View
public SelectFrom<Parent>.View parentTran;
/// Child view
public SelectFrom<Child> .Where<Child.tranId.IsEqual<Parent.nCTranId.AsOptional>>.View
childAnalysis;
#region TranId
// Child DAC Field.
public abstract class tranId:PX.Data.BQL.BqlInt.Field<tranId> {
}
[PXDBInt(IsKey = true)]
[PXDBDefault(typeof(Parent.nCTranId))]
[PXParent(typeof(Select<Parent, Where<Parent.nCTranId, Equal<Current<tranId>>>>))]
public virtual int? TranId {
get; set;
}
#endregion
Take a look at T210 regarding Master-Detail Relationships. It contains a section on inserting a default record, which sounds like what you are trying to do with your child DAC. The training can be found at https://openuni.acumatica.com/courses/development/t210-development-customized-forms-and-master-detail-relationship/ on the Acumatica website. Specifically look at pages 103 and 104.
In step 3 of the section, you will see use of the RowInserted event to insert the child record. Since the RowInserted event fires only when creating a record, making it safe to insert the child record.
See the following code sample. I tried to use as much of your sample as possible, but I merged it with the technique shown in the training guide. Disclaimer: It will compile, but I have not built the prerequisites to fully test the code.
using PX.Data;
using PX.Data.BQL.Fluent;
namespace SSCS.CodeSample
{
public class CodeSampleEntry : PXGraph<CodeSampleEntry, DACParent>
{
#region Data Views
/// Parent View
[PXViewName("Parent View - Primary")]
public SelectFrom<DACParent>.View ParentTran;
/// Child view
[PXViewName("Child View")]
public SelectFrom<DACChild>
.Where<DACChild.tranId.IsEqual<DACParent.nCTranId.FromCurrent>>
.View ChildAnalysis;
#endregion
// RowInserted Event to Create a Default Child Record
// See T210 Master-Detail training guide from Acumatica
protected virtual void _(Events.RowInserted<DACParent> e)
{
// Ensure there isn't a child record already
if (ChildAnalysis.Select().Count == 0)
{
// Save state of IsDirty so that we can restore it
// after inserting the default child record
// so that we don't force the user to save
// unless they actually enter data somewhere
bool oldDirty = ChildAnalysis.Cache.IsDirty;
// Create an object for the child
// and fill in any data that should be
// populated by default
DACChild newChild = new DACChild();
newChild.MyData = "My Value";
// Insert the new child record into the cache
ChildAnalysis.Insert(newChild);
// Restore the IsDirty flag
// The insert above will have marked the view as
// dirty. If it wasn't dirty before, it should be
// treated as if it still isn't
ChildAnalysis.Cache.IsDirty = oldDirty;
}
}
}
[PXCacheName("Parent DAC")]
public class DACParent : IBqlTable
{
#region NCTranId
[PXDBIdentity]
public virtual int? NCTranId { get; set; }
public abstract class nCTranId
: PX.Data.BQL.BqlInt.Field<nCTranId> { }
#endregion
}
[PXCacheName("Child DAC")]
public class DACChild : IBqlTable
{
#region TranId
[PXDBInt(IsKey = true)]
[PXDBDefault(typeof(DACParent.nCTranId))]
[PXParent(typeof(SelectFrom<DACParent>
.Where<DACParent.nCTranId.IsEqual<DACChild.tranId.FromCurrent>>))]
public virtual int? TranId { get; set; }
public abstract class tranId
: PX.Data.BQL.BqlInt.Field<tranId> { }
#endregion
#region MyData
[PXDBString()]
[PXUIField(DisplayName = "My Data Field")]
public virtual string MyData { get; set; }
public abstract class myData
: PX.Data.BQL.BqlString.Field<myData> { }
#endregion
}
}

How to activate the filtering action for a user field added to a grid

I have a customization to the Release Time Activities screen (EP507020) where I add a user field. This user field will contain the result of fetching the Appointment status from the Appointments screen (FS300200) based on the Appointment ID that I've also added to the Release Time Activities screen grid.
This was done so that the process grid could be filtered for appointment status that were a certain value. The Appointment Status User field I've added contains the same attributes that the Status field contains on the Appointments screen, with the Cache extension looking as follows:
#region UsrApptStatus
public abstract class usrApptStatus : IBqlField
{
}
[PXDBString(1)]
[FSAppointment.status.ListAtrribute]
[PXUIField(DisplayName = "Appt Status",Enabled = false)]
public virtual string UsrApptStatus { get; set; }
#endregion
This works fine when I fetch the status as follows in a Graph extension:
protected virtual void EPActivityApprove_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
var epactivityapprove = (EPActivityApprove)e.Row;
if (epactivityapprove != null)
{
FSxPMTimeActivity rowExt = epactivityapprove.GetExtension<FSxPMTimeActivity>();
if (rowExt != null)
{
var appointmentID = rowExt.AppointmentID;
var fsappt = (FSAppointment)PXSelect<FSAppointment,
Where<FSAppointment.appointmentID, Equal<Required<FSAppointment.appointmentID>>>>.Select(Base, appointmentID);
var epactivityapproveext = PXCache<EPActivityApprove>.GetExtension<EPActivityApproveExt>(epactivityapprove);
epactivityapproveext.UsrApptStatus = fsappt.Status;
}
}
}
The problem is that when I go to filter the Status column, no matter what I choose from the list of options, it clears all rows. I have no idea why this wouldn't work, but I'm sure I'm missing something.
Grid before filtering:
Filter:
Grid after filter:
It seems to me that changing the value in the RowUpdated event is interfering with the filter. If you wrote both extensions, it would help to have both custom fields in the same extension and use the PXFormula attribute to set the value of your status based on the AppointmentID field. This way you wouldn't have to rely on the event:
#region UsrApptStatus
public abstract class usrApptStatus : IBqlField
{
}
[PXDBString(1)]
[FSAppointment.status.ListAtrribute]
[PXFormula(typeof(Selector<appointmentID, FSAppointment.status>))]
[PXUIField(DisplayName = "Appt Status",Enabled = false)]
public virtual string UsrApptStatus { get; set; }
#endregion

How can I get the appointment status on the Release Time Activities screen

I'm customizing the Release Time Activities screen (EP507020) in the following ways:
First, I'm putting the Appointment Number in the grid via the 'Add Data Fields' option in the screen customization.
Second, I want to tie back to the Appointments screen (FS300200) via the Appointment Nbr to get the status.
Third, I want to add a user field to the Time Activities grid to hold this obtained status so that the grid can be filtered by the status.
I've run into several problems, the largest of which is that even though I can add the Appointment Number to the Release Time Activities screen grid - and upon inspection it shows that it belongs to the same DAC as all the other fields in that grid - it show NO WHERE in the DAC when I bring up the source code. It isn't in any table I can find either. This is a complete mystery - how can a field show on the inspection window as part of a DAC when it really isn't?
Next - there are two fields in the DAC for the Appointments screen DAC (FSAppointment) - RefNbr (which is the Appointment Number) and the AppointmentID (which is an auto-incrementing identity field). Which one would I use to tie back to the Appointments screen to link the Appointment Nbr (if that's even possible)?
The main issue is that I cannot find the Appointment Nbr in the DAC (EPActivityApprove) to even tie back to the Appointments screen.
Is this something doable?
The Activity dataview bound to Release Time Activities screen (EP507020) grid contains multiple DACs:
public PXFilteredProcessingJoin<
EPActivityApprove,
EPActivityFilter,
LeftJoin<EPEarningType,
On<EPEarningType.typeCD, Equal<EPActivityApprove.earningTypeID>>,
InnerJoin<EPEmployee,
On<EPEmployee.userID, Equal<EPActivityApprove.ownerID>,
And<Where<EPEmployee.timeCardRequired, NotEqual<True>, Or<EPEmployee.timeCardRequired, IsNull>>>>,
LeftJoin<CRActivityLink,
On<CRActivityLink.noteID, Equal<EPActivityApprove.refNoteID>>,
LeftJoin<CRCase,
On<CRCase.noteID, Equal<CRActivityLink.refNoteID>>,
LeftJoin<CRCaseClass,
On<CRCaseClass.caseClassID, Equal<CRCase.caseClassID>>,
LeftJoin<ContractEx,
On<CRCase.contractID, Equal<ContractEx.contractID>>>>>>>>
[...]
Looking at the main DAC we see it extends PMTimeActivity so it will contain all fields of that DAC too:
public class EPActivityApprove : PMTimeActivity
PMTimeActivity doesn't contain AppointmentID either but another DAC named FSxPMTimeActivity does and it also extends PMTimeActivity. That's the reason why you're seeing that field available in EPActivityApprove:
public class FSxPMTimeActivity : PXCacheExtension<PMTimeActivity>
{
#region AppointmentID
public abstract class appointmentID : PX.Data.IBqlField
{
}
[PXDBInt]
[PXUIField(DisplayName = "Appointment Nbr.")]
[PXSelector(typeof(Search<FSAppointment.appointmentID>),
SubstituteKey = typeof(FSAppointment.refNbr))]
public virtual int? AppointmentID { get; set; }
#endregion
}
Given an EPActivityApprove object I think you can get a reference to the extension containing AppointmentID like this:
EPActivityApprove row = ???;
FSxPMTimeActivity rowExt = row.GetExtension<FSxPMTimeActivity>();
int? appointmentID = rowExt.AppointmentID;
As for the joins, you must specify each key field (IsKey = true) from the DAC.
For FSAppointment these would be SrvOrdType and RefNbr (appointmentID is not a key field in that DAC):
#region SrvOrdType
public abstract class srvOrdType : PX.Data.IBqlField
{
}
[PXDBString(4, IsFixed = true, IsKey = true, InputMask = ">AAAA")]
[PXDefault(typeof(FSSetup.dfltSrvOrdType))]
[PXUIField(DisplayName = "Service Order Type")]
[FSSelectorSrvOrdTypeNOTQuote]
[PX.Data.EP.PXFieldDescription]
public virtual string SrvOrdType { get; set; }
#endregion
#region RefNbr
public abstract class refNbr : PX.Data.IBqlField
{
}
[PXDBString(20, IsKey = true, IsUnicode = true, InputMask = "CCCCCCCCCCCCCCCCCCCC")]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "Appointment Nbr.", Visibility = PXUIVisibility.SelectorVisible, Visible = true, Enabled = true)]
[PXSelector(typeof(
Search2<FSAppointment.refNbr,
LeftJoin<FSServiceOrder,
On<FSServiceOrder.sOID, Equal<FSAppointment.sOID>>,
LeftJoin<Customer,
On<Customer.bAccountID, Equal<FSServiceOrder.customerID>>,
LeftJoin<Location,
On<Location.locationID, Equal<FSServiceOrder.locationID>>>>>,
Where<
FSAppointment.srvOrdType, Equal<Optional<FSAppointment.srvOrdType>>>,
OrderBy<Desc<FSAppointment.refNbr>>>),
new Type[] {
typeof(FSAppointment.refNbr),
typeof(Customer.acctCD),
typeof(Customer.acctName),
typeof(Location.locationCD),
typeof(FSAppointment.docDesc),
typeof(FSAppointment.status),
typeof(FSAppointment.scheduledDateTimeBegin)
})]
[AppointmentAutoNumber(typeof(
Search<FSSrvOrdType.srvOrdNumberingID,
Where<
FSSrvOrdType.srvOrdType, Equal<Optional<FSAppointment.srvOrdType>>>>),
typeof(AccessInfo.businessDate))]
[PX.Data.EP.PXFieldDescription]
public virtual string RefNbr { get; set; }
#endregion
EDIT:
Took a better look at it, I don't think you'll be able to join on the key fields. Because AppointmentID is a Unique Identifier field you can make an exception in this case and join only on that field because it will behave as a single key field.

Setting Custom Field on new BAccount Object

I am trying to set a custom field on a brand new BAccount object created via the action ConvertToBAccount() in the Contact BLC. I've tried quite a few different things including overriding the action and trying to set the value on the object after the action is complete and navigates to the BAccount BLC. I found that I can't set the value on the override because there is no record in the database until the user manually saves, and when I try to set the value after the action, it sets the field, but does not show the new value on the screen when the BAccount BLC is done loading.
How can I set an extension field for a new BAccount created via the ConvertToBAccount() action on the Contacts BLC?
DAC Extension:
public class BAccountExt : PXCacheExtension<PX.Objects.CR.BAccount>
{
#region UsrHomeCampus
[PXDBInt]
[PXUIField(DisplayName="Home Campus")]
[PXSelector(typeof(Search<PX.Objects.GL.Branch.branchID>),
typeof(PX.Objects.GL.Branch.branchCD),
SubstituteKey = typeof(PX.Objects.GL.Branch.branchCD))]
public virtual int? UsrHomeCampus { get; set; }
public abstract class usrHomeCampus : IBqlField { }
#endregion
}
BLC Code:
public class BusinessAccountMaint_Extension : PXGraphExtension<BusinessAccountMaint>
{
#region Event Handlers
protected void Contact_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
Contact row = (Contact)e.Row;
if (row.ContactID > 0 && Base.CurrentBAccount.Current.BAccountID < 0)
{
Base.CurrentBAccount.Current.GetExtension<BAccountExt>().UsrHomeCampus = row.GetExtension<ContactExt>().UsrHomeCampus;
//Save record in database
Base.Actions.PressSave();
//Cause page refresh
Base.Actions.PressCancel();
}
}
#endregion
}
When a BAccount is being created from Contact by ConvertToBAccount() method the BAccountID of the newly created BAccount is being set to Contact's BAccountID field.
You should take that BAccount for example by querying something like this
BAccount bAccount = PXSelect<BAccount,Where<BAccount.bAccountID,Equal<Required<BAccount.bAccountID>>>.Select(graph,contactObject.BAccountID);
Then get you extension like this:
BAccountExt acc = PXCache<BAccount>.GetExtension<BAccountExt>(bAccount);
And set the values that you need and then update the BAccount in some way like this:
this.Base.BAccountsView.Update(bAccount);
this.Base.Save.Press();

Hide/Disable other fields based on Input field

I want to hide or update a field on the UI based on conditions of another field.
For example, if I have a field called Color:
[PXUIField(DisplayName="Color")]
[PXStringList("Red,Blue,Other")]
[PXDefault("Red")]
And text field for comments only shown when "Other" is selected, how is this accomplished?
The requested behavior can either be accomplished either with a series of event handlers or with a bunch of attributes. You can find several examples on how to subscribe to the RowSelected and FieldUpdated events in the T200 training course, available at Acumatica University and Acumatica Open University
Going with field attributes is a more convenient and way easier option for your particular scenario. I would recommend setting CommitChanges to True for the drop-down, so the Comments field is cleared and disabled/enabled immediately after the user updates Color. Also, it's very to have your Color declared after Comments, so the framework will process Comments field first and always clear the current Comments value after the Color field got updated.
public class Other : Constant<string>
{
public Other() : base("Other") { }
}
public abstract class comments : IBqlField { }
[PXDBString(255, IsUnicode = true)]
[PXUIField(DisplayName = "Comments")]
[PXUIEnabled(typeof(Where<color, Equal<Other>>))]
[PXFormula(typeof(Default<color>))]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
public string Comments { get; set; }
public abstract class color : IBqlField { }
[PXDBString(10, IsUnicode = true)]
[PXUIField(DisplayName = "Color")]
[PXStringList("Red,Blue,Other")]
[PXDefault("Red")]
public string Color { get; set; }
The only way to conditionally hide/show editor on a form is though the RowSelected event handler:
public void YourDAC_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
YourDAC row = e.Row as YourDAC;
if (row == null) return;
PXUIFieldAttribute.SetVisible<YourDAC.comments>(sender, row, row.Color == "Other");
}
I believe, in the T200 training course, there are several examples on the PXUIFieldAttribute.SetVisible method.

Resources