How to edit the CashAccount attribute globally - acumatica

I need to add two inner joins and a Where clause to any search that is used on a CashAccount attribute. I want to make this change globally so that all fields that have the CashAccount attribute are limited by the Where clause that I want to add. I'm trying to avoid having to hunt down every field that has the CashAccount attribute and either change the Search<> that it's using or replace the CashAccount attribute with a custom one. Is it possible?
For instance, on this constructor for the CashAccount attribute, I want to add 2 Inner Joins and a Where to the "search" parameter that is passed in to the constructor.
/// <summary>
/// Constructor of the new CashAccountAttribute object. Filter by branch, doesn't suppress <see cref="CashAccount.Active"/> status verification.
/// </summary>
/// <param name="branchID">Identifier for the branch.</param>
/// <param name="search">The type of search. Should implement <see cref="IBqlSearch"/> or <see cref="IBqlSelect"/></param>
public CashAccountAttribute(Type branchID, Type search) : base(branchID, search)
{
}
I've tried overriding the CacheAttached event in order to append two joins to the search that is passed into my custom attribute but, this is giving an error on Cash Sale screen when I select the Customer for the Cash Sale. I made this change on the Cash Sale screen only. I replaced the CashAccount attribute and replaced it with a custom attribute that inherits the CashAccount attribute.
public override void CacheAttached(PXCache sender)
{
base.CacheAttached(sender);
BqlCommand oldbql = this.SelectorAttribute.GetSelect();
BqlCommand newbql = BqlCommand.AppendJoin(oldbql, typeof(InnerJoin<Branch, On<Branch.branchID, Equal<Current<CashAccount.branchID>>>>));
newbql = BqlCommand.AppendJoin(newbql, typeof(InnerJoin<Organization, On<Organization.organizationID, Equal<Current<Branch.organizationID>>>>));
this._Attributes.Remove(this.SelectorAttribute);
PXDimensionSelectorAttribute selectorAttr = new PXDimensionSelectorAttribute("CASHACCOUNT",newbql.GetType());
this._Attributes.Add(selectorAttr);
}
Any ideas would be great.
TIA!

I needed to alter an attribute globally as well, and I think what you describe is a 2-step process as outlined here.
First you want to create your own attribute inheriting from the original. (I know, you said you want to replace the other attribute globally, but that's accomplished in step 2 if this method works for you as it did for me.) Make the adjustments in your attribute so that it works when you use it directly. This is purely for testing purposes that you use it directly.
Second, use a DAC extension or graph extensions (using cacheattached) to use YOUR attribute. If the DAC is extended to replace it, then everywhere the DAC is used should be impacted. If the attribute is used within graphs, this may mean adding graph extensions for each one to use cacheattached to do the same thing within those graphs.
Please note that you will need to remove the original attribute with
[PXRemoveBaseAttribute(typeof(CashAccountAttribute))]
and then add your new attribute.

Related

Is there a way to prevent creation of a data class item in C# WindowsForms UserControl

If I create a UserControl, to create and edit an instance of a data class e.g. Person in C# WindowsForms (call it PersonControl), the framework automatically adds an instance of Person in PersonControl.Designer with some default values for the properties and fills the item controls with those values. This behavior has a number of side effects which I would like to avoid.
Question: is there a defined way to prevent creation of a data class instance in UserControl.Designer?
I think you missing the DesignerSerializationVisibility attribute. If you have a custom control every public property that you add will automatically be serialized. You can use this attribute to disable the serialization for a property. I also recommend to add the Browsable attribute which will hide the property from the designer. If you want more control over serialization, like you want to serialize only when another property is set to true you can create a special named method which will then called by the designer Defining Default Values with the ShouldSerialize and Reset Methods. There was a MSDN Magazine where a lots of winform learning resource was relased there are some gems about winform internal working. If you interested in you can quickly look trhrough it. My favorite is. Create And Host Custom Designers With The .NET Framework 2.0
Sorry but i didn't mention another attribute DefaultValue You can use the attribute the following way.
public partial class PersonEditControl : UserControl
{
[DefaultValue(null)] // This attribute tells the designer if the property value matches what we specified in the attribute(null) it should not store the property value.
public PersonData? Person { get; set; }
public PersonEditControl()
{
InitializeComponent();
}
}

I can't get the launch function to work on the Related Entity control

This relates to and extends an existing StackOverflow case that has been answered -
How to place a 'Related Entity' lookup on a field (many thanks to Acumatica support on this as well)
I have a custom screen that adds a 'Related Link' control, like this:
And this works as expected. I've also included several custom screens as entities to link to by adding the NoteID, RefNoteID, RelatedEntity fields to their DACs and the PXRefNoteSelector attribute to their view declarations. Everything works as expected, except that the pencil icon doesn't launch to the entity / screen that's been selected.
Is there something (an attribute, perhaps) that I'm missing in the DACs that needs to be added in order to launch to the selected entity?
You need to decorate the custom entity DAC with PXPrimaryGraph attribute and pass the maintenance page graph type in parameter:
[PXPrimaryGraph(typeof(CustomEntityMaint))]
[Serializable]
public class CustomEntityDAC : PX.Data.IBqlTable
{
}

Limiting Projects based on selector

I would like to filter the records shown on the Projects screen. I've been given the directive to see if limiting the Selector for projects (re-writing the PXSelector for the ProjectID?) would also limit the records that show up on the screen, i.e., a user would not be able to navigate to records that aren't displayed by the Selector. I don't think that's the case, as the screen's view is not limited by what is chosen by the Selector - but I wanted to verify this.
Also - as far as limiting the records that show up in the Selector (possibly re-writing the Selector/BQL using a where clause?) - I looked at the source DAC, and for the life of me I can't figure it out. There is a PXSelector on the ContractID, which doesn't use the SubstituteKey that I'm familiar with, and the ContractCD also has several attributes with which I'm unfamiliar - namely the PXRestrictor AND the PXDimensionSelector.
Bottom line:
1.) What's the best way to limit the records for Project shown in the screen's Selector? Can I just add to the PXRestrictor attribute?
2.) Would limiting the Selector's results also limit what the user can navigate to on the screen using the navigation buttons?
Whenever you need to restrict access to primary records on a data entry screen, it's always required to customize both the lookup DAC key field and the primary data view. By design, in Acumatica key fields in DAC and the primary data view are completely independent, that is why it's required to modify both pieces to achieve the desired result.
For example, to deny access to canceled projects on the Projects screen, you should add PXRestrictorAttribute to PMProject's ContractCD field and also re-declare Project primary data view:
public class ProjectEntryExt : PXGraphExtension<ProjectEntry>
{
public class cancelled : Constant<string>
{
public cancelled() : base(ProjectStatus.Cancelled) {; }
}
[PXViewName(Messages.Project)]
public PXSelect<PMProject, Where<PMProject.baseType, Equal<PMProject.ProjectBaseType>,
And<PMProject.nonProject, Equal<False>, And<PMProject.isTemplate, Equal<False>,
And<PMProject.status, NotEqual<cancelled>,
And<Match<Current<AccessInfo.userName>>>>>>>> Project;
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXRestrictor(typeof(Where<PMProject.status, NotEqual<cancelled>>),
"Given Project/Contract '{0}' is cancelled", typeof(PMProject.contractCD))]
public void PMProject_ContractCD_CacheAttached(PXCache sender) { }
}

Acumatica: Getting value of field on header from grid event

I'm new to Acumatica custom development and I'm trying to do something that I would assume is very simple. I have a Selector control (DataClass: FSServiceOrder, DataField: BranchLocationID) in the Sales Order header that allows user to set the Branch Location. Below, in an Inventory grid, I merely want to set the Warehouse field in the new row equal to the value of the above-mentioned selector. I can set Warehouse with a hard-coded value, but I have no idea how to reference the selector or get it's value, as it seems to be outside the scope of the passed PXCache object:
protected void FSSODetPart_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
string BranchLocationID = "" // Not sure how to get this value
var row = (FSSODetPart)e.Row;
cache.SetValueExt(row, "SiteID", BranchLocationID);
}
I was hoping I could simply reference all UI controls similar to ASP.NET, but that doesn't seem to be the case. Any help is appreciated. Getting a value from the screen seems to be fundamental but I cannot find any help in the documentation. Thanks.
In Acumatica screen controls are bound to DataViews.
DataViews contains DAC records. Common practice is to get the value from the current DAC record in the bound DataView.
Use the current object of the DataView holding FSServiceOrder DAC records:
string BranchLocationID = myDataview.Current.BranchLocationID;
If you don't know the DataView name, on the WebSite hold Ctl+Alt and click on the BranchLocationID UI field. A popup will appear showing the DataView name.
Getting the current object from the DAC collections should work too but it's preferable to use the DataView:
string BranchLocationID = Base.Caches[typeof(FSServiceOrder)].Current.BranchLocationID;
Also make sure you set the CommitChanges attribute to true on BranchLocationID form field in the Aspx file. This ensures that current object will fire events in the back-end when it's value is changed.
<px:PXSelector ID="edBranchLocationID" runat="server"
DataField="BranchLocationID" CommitChanges="True" />

CRAttributeList extension with Acumatica

Currently I work with screen ap303000.aspx. I want to add new attribute to tab "Attributes". This tab is binded to view "Answers" which is declared in following way:
[PXViewName(CR.Messages.Answers)]
public CRAttributeList<Vendor> Answers;
little bit digging with metadata viewer in CRAttributeList shows that CRAttributeList is inherited from PXSelectBase and definitely reads records from CSAnswers table:
public class CRAttributeList<TReference> : PXSelectBase<CSAnswers> where TReference : IBqlTable
which gives me hint, that I need to insert something into table CSAnswers. Table CSAnswers by it's structure also doesn't give me enough information what should I put in table CSAnswers in order to have some attribute as bool and available to all Vendors and to turn it on by default?
You need to specify list of Attributes at Vendor Class (AP201000) level first.
Once Vendor class is specified, Attributes specified at Class level will be listed for which value can be assigned.

Resources