Custom Selector not refreshing when placed in Grid - acumatica

I have a custom Selector created using PXCustomSelectorAttribute class, I am not able to do AutoRefresh as this option is not available. Can anyone tell me how to Autorefresh the custom selector.

Below is an example how to create a CustomSelector and set it to AutoRefresh mode.
using PX.Objects.SO;
using PX.Objects.AR;
using PX.Data;
using System.Collections;
namespace TestLib
{
public class SOOrderExt : PXCacheExtension<SOOrder>
{
#region UsrTestField
[PXDBString]
[PXUIField(DisplayName = "TestField")]
[CustomerPriceClass()]
public virtual string UsrTestField { get; set; }
public abstract class usrTestField:IBqlField { }
#endregion
}
public class CustomerPriceClassAttribute : PXCustomSelectorAttribute
{
public CustomerPriceClassAttribute()
: base(typeof(ARPriceClass.priceClassID))
{
this.DescriptionField = typeof(ARPriceClass.description);
}
protected virtual IEnumerable GetRecords()
{
ARPriceClass epc = new ARPriceClass();
epc.PriceClassID = ARPriceClass.EmptyPriceClass;
epc.Description = PX.Objects.AR.Messages.BasePriceClassDescription;
yield return epc;
foreach (ARPriceClass pc in PXSelect<ARPriceClass>.
Select(this._Graph))
{
yield return pc;
}
}
}
}
After this you need to add the field to the UI from Layout Editor and set the AutoRefresh property in the Ext Properties section to True. See the screen-shot below.
UPDATE:
In case of Grid you need to add you will need to add Control in the Levels of the Grid like is shown on the screenshot below:
After adding the control you will see the Field Editor (3) for that field.
In the properties of the Field Editor the AutoRefresh is available and you can set it to True:

Related

How to fire FieldSelecting event only in the screen?

I have a number of non persistent fields that get its value via FieldSelecting events. The events do the same queries and calculations so I decided to move them into an attribute that implements IPXFieldSelectingSubscriber interface. This works fine and it minimises duplicate codes. However, the event fires every single time the DAC is accessed. Be that in GIs or called in some other graphs. Is there such a flag to verify if the event is being fired only from a specific screen ?
The easiest way to do that would be to add the validation of which screen is accessing the DAC, you can do that by simply putting an if statement like below into your event handler.
if(graph.Accessinfo.ScreenID == "SO.30.10.00")
{
//execute the logic
}
else
{
//skip
}
An alternative solution would be to have the base field type declared on your DAC and then within a graph extension specific to the page you want the logic on, you would declare a CacheAttached event with the custom attribute.
DAC field :
public sealed class APInvoiceExtension : PXCacheExtension<APInvoice>
{
#region UsrTotal
public abstract class usrTotal : BqlDecimal.Field<usrTotal>
{
}
[PXDBDecimal]
[PXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "Total")]
public decimal? UsrTotal { get; set; }
#endregion
}
Graph Extension :
public class APInvoiceEntryExtension : PXGraphExtension<APInvoiceEntry>
{
[PXMergeAttributes(Method = MergeMethod.Append)]
[CustomCalculationAttribute]
protected virtual void __(Events.CacheAttached<APInvoiceExtension.usrTotal> e)
{
}
}

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

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.

How to get DAC record from Note Table

Does anyone have a code snippet on how to go from RefNoteId => DAC when I dont know what dac type the note is attached to?
I have made it this far (row.RefNoteID is what I am starting from)
Note note = PXSelect<Note, Where<Note.noteID, Equal<Required<Note.noteID>>>>.Select(this, row.RefNoteID);
Type recordType = Type.GetType(note.EntityType);
PXCache recordCache = Caches[recordType];
How can I now do a PXSelect<recordType, Where<recodType.noteID, Equal<Required<recordType.noteID>>>>.Select(GRAPH) ? The recordType could be any DAC in the system that has a noteID.
Thanks
The below code works for me and it is based on the way Acumatica gets the record inside the PXRefNoteSelectorAttribute.PrimaryRow_RowPersisted.
The problem with this approach is that this will work for Header entities like SOOrder, INRegister, SOInvoice, SOShipment, and others. But for "detail" entities like SOLine, INTran, and others this approach will work only if that corresponding record has some Note related to Text/File. Acumatica is adding records corresponding to their NoteID into the Note table only if that detail records have some Note/Text. My best guess is that this is done in order to avoid over-spamming the Note table.
using PX.Data;
using PX.Objects.SO;
using System;
using System.Collections;
using System.Linq;
using System.Web.Compilation;
namespace SearchByNoteID
{
// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
public PXAction<SOOrder> searchByNoteID;
[PXUIField(DisplayName ="Search by Note ID")]
[PXButton(CommitChanges = true)]
public virtual IEnumerable SearchByNoteID(PXAdapter adapter)
{
var order = adapter.Get<SOOrder>().FirstOrDefault();
if(order!=null)
{
//
//...
//
Guid? noteID = GetNoteID();
object record = GetRecordByNoteID(noteID);
//
//... do whatever you want with the record
//
}
return adapter.Get();
}
protected object GetRecordByNoteID(Guid? noteID)
{
var type = GetEntityType(this.Base, noteID);
if(type==null) return null;
object entityRow = new EntityHelper(this.Base).GetEntityRow(type, noteID);
return entityRow;
}
protected Type GetEntityType(PXGraph graph, Guid? noteID)
{
if (noteID == null)
{
return null;
}
Note note = PXSelectBase<Note, PXSelect<Note, Where<Note.noteID, Equal<Required<Note.noteID>>>>.Config>.SelectWindowed(graph, 0, 1, new object[]
{
noteID
});
if (note == null || string.IsNullOrEmpty(note.EntityType))
{
return null;
}
return PXBuildManager.GetType(note.EntityType, false);
}
}
}

Button not showing in the UI

I'm extending the AccountByPeriodEnq logic, I just want to add a button on top of my screen to modify the selected GL records but it just doesnt want to show up and I can't figure out why.
Here's my code :
namespace PX.Objects.GL
{
class AccountByPeriodEnqExtensions : PXGraphExtension<AccountByPeriodEnq>
{
#region Actions
public PXAction<AccountByPeriodFilter> Letter;
[PXUIField(Visible = true, DisplayName = "Lettrer")]
[PXButton(CommitChanges = true)]
protected virtual IEnumerable letter(PXAdapter adapter)
{
IReadOnlyCollection<GLTranR> selectedTrans = GetSelectedTrans();
if (selectedTrans.Any())
{
PXLongOperation.StartOperation(this, delegate ()
{
foreach(GLTranR line in selectedTrans)
{
// UpdateSomeFieldsAndPersists
}
});
}
else
{
throw new PXException("Error");
}
return Base.Filter.Select();
}
#endregion
#region Utility
private IReadOnlyCollection<GLTranR> GetSelectedTrans()
{
return Base.GLTranEnq.Cache.Updated
.Cast<GLTranR>()
.Where(tran => tran.Selected == true)
.ToArray();
}
#endregion
}
}
Is there anything I'm missing here ?
Regards,
Edit:
To clarify i'm trying to customize the GL404000, Account Details. And using the inspector I saw the Business logic is in the AccountByPeriodEnq Graph
Using Acumatica Inspect Element feature notice that the 'Account by Period' screen (GL402000) is not using the 'AccountByPeriodEnq' graph.
It is using the 'AccountHistoryByYearEnq' graph instead so that's the graph you want to target:
You also need to declare Actions on the primary DAC of that Graph.
The one for 'AccountHistoryByYearEnq' is a little bit harder to find than usual.
You can use Acumatica Source Code page and search for 'PXPrimaryGraph(typeof(AccountHistoryByYearEnq)':
In this case it is AccountByYearFilter DAC that you should use:
[System.SerializableAttribute()]
[PXCacheName(Messages.Account)]
[PXPrimaryGraph(typeof(AccountHistoryByYearEnq), Filter = typeof(AccountByYearFilter))]
public partial class Account : PX.Data.IBqlTable, PX.SM.IIncludable
{
[…]
}
I think this is a special case for Filter, when there's no filter Account would have been the DAC to use for the Actions.
Now that you have identified the Primary Graph of the Screen (AccountHistoryByYearEnq) and the Primary DAC of the Graph (AccountByYearFilter) it should work as expected:
public class AccountByPeriodEnq_Extension : PXGraphExtension<AccountHistoryByYearEnq>
{
public PXAction<AccountByYearFilter> letter;
[PXUIField(DisplayName = "Letter")]
[PXButton]
protected virtual IEnumerable Letter(PXAdapter adapter)
{
return adapter.Get();
}
}
UI:
EDIT:
For Account detail page (GL404000), use the same code with different DAC and Graph:
using PX.Data;
using System.Collections;
namespace PX.Objects.GL
{
public class AccountByPeriodEnq_Extension : PXGraphExtension<AccountByPeriodEnq>
{
#region Actions
public PXAction<AccountByPeriodFilter> letter;
[PXUIField(DisplayName = "Letter")]
[PXButton]
protected virtual IEnumerable Letter(PXAdapter adapter)
{
return adapter.Get();
}
#endregion
}
}
With a base Acumatica install that's all that is needed for the Action to appear:
Note that you can specify explicit state and view rights for the button control, though I don't think your issue is related to access rights if you're working in a developer instance:
[PXUIField(DisplayName = "Letter",
MapEnableRights = PXCacheRights.Select,
MapViewRights = PXCacheRights.Select)]
I finally found my problem, I missed the public member for my class.
namespace PX.Objects.GL
{
public class AccountByPeriodEnqExtensions : PXGraphExtension<AccountByPeriodEnq>
{
#region Actions
public PXAction<AccountByPeriodFilter> Letter;
Thanks for your answer HB, i'll reuse it.

Render Action button

I was creating a new Screen with the FormDetail template where I would be having a Filter DAC and list of DAC to display on Grid. I created the page successfully. Then,I wanted to put a button on the top of the button which would pull data from api and refresh grid. So, I wrote the below code to render an action button on page(FormDetail) like this.
But, it is not working.
using System;
using PX.Data;
namespace AcumaticaSquarePOSIntegration
{
public class SquarePOSTransactionInquiry : PXGraph<SquarePOSTransactionInquiry>
{
public PXSave<MasterTable> Save;
public PXCancel<MasterTable> Cancel;
public PXFilter<MasterTable> MasterView;
public PXFilter<DetailsTable> DetailsView;
public PXAction<MasterTable> Calc;
[PXUIField(DisplayName="Calc")]
[PXButton]
protected virtual IEnumerable calc(PXAdapter adapter)
{
return adapter.Get();
}
[Serializable]
public class MasterTable : IBqlTable
{
}
[Serializable]
public class DetailsTable : IBqlTable
{
}
}
}
I even tried add
Is there anything that I am missing here?
You have two PXFilters, change the second to PxSelect and make the PXFilter your first Data view in the list.
try using PXProcessButton instead of PXButton.
Also make sure MasterView is specified in aspx as a PrimaryView.

Resources