Pxfilteredprocessing In Acumatica

PXFilteredProcessing in Acumatica

Hello everybody,

few day ago I was digging in code of CT502000, and found interesting part of code:

public PXFilteredProcessing<ContractsList, ExpiringContractFilter> Items;

As usually in my code I use PXFilter, and discovery of PXFilteredProcessing was confusting for me. 

The first think that I as usually do, if I see something new, it is watching with reflector in declaration of new type. Here it what reflector shows:

public class PXFilteredProcessing<Table, FilterTable> : PXProcessing<Table> 
where Table: class, IBqlTable, new() where FilterTable: class, IBqlTable, new()

This means, that we can pass into PXFilteredProcessing two tables. T200 manual gives an answer why: Provides data records for processing with filtering. This data type takes two DACs as type parameters, where the second DAC specifies the filter DAC. You can use the

Where<>and OrderBy<>clauses in this data view type. It means, that items in Table will be filtered according to FilterTable. 

No Comments

Add a Comment

Select All Rows In Acumatica

Select all rows in Acumatica

Hello everybody,

today I want to share one simple trick. Sometime in grid you have chekcboxes, and you can have a need to make all of them selected. Here is sample of code which helps with this task:

<px:PXGridColumn AllowCheckAll="True" AllowNull="False" DataField="Selected" TextAlign="Center" Type="CheckBox" Width="30px" />

No Comments

Add a Comment

Pxsmartpanel In Acumatica

PXSmartPanel in Acumatica

Hello everybody,

today I want to write few words how to work with PXSmartPanel.

One of my clients asked following:

1. Press at button.

2. Pop up should appear with two buttons ( "OK" , "Cancel")

3. At pop up should be also selector of contracts and datetime.

4. Existing screen should be modified.

In order to do this, following actions were implemented:

1. Existing screen was CT301000.

2. If to look in screen source code, following line says about graph:

<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" TypeName="PX.Objects.CT.ContractMaint"
        PrimaryView="Contracts" BorderStyle="NotSet">

3. It means, that we need to create extension class for ContractMaint.

4. For example like this:

public class ContractMaintExt : PXGraphExtension<ContractMaint>
{

        [PXCopyPasteHiddenView]
        public PXFilter<SubstituteSettingsFilter> SubstituteSettings;
        public PXAction<Contract> Substitute;
        [PXButton(CommitChanges = true)]
        [PXUIField(DisplayName = "Substitute")]
        protected void substitute()
        {
            if (this.SubstituteSettings.AskExt(new PX.Data.PXView.InitializePanel(this.fillFilter)) ==
                WebDialogResult.OK)
            {
                var subsFilter = (SubstituteSettingsFilter)this.SubstituteSettings.Cache.Current;
                CopyOpenPMTaskHistory(Base.Contracts.Current.ContractID, subsFilter.ContractID, subsFilter.TransitionDate);
            }
        }
}

5. In the line 4 we declared to Acumatica, that we want to extend ContractMaint, and we want to create some data input, which is related to SubstituteSettingsFilter. Take note of Substitute and substitute: both of them are needed in order to make processing of inputted values.

6. Take a look at SubstituteSettingsFilter class itself:

 [Serializable]
        public class SubstituteSettingsFilter  : IBqlTable
        {
            #region contractID

            public abstract class contractID : IBqlField, IBqlOperand
            {
            }

            protected int? _ContractID;
            [PXDefault]
            [PXDBInt]
            [PXDimensionSelector("CONTRACT", typeof(Search2<Contract.contractID, 
                InnerJoin<ContractBillingSchedule, On<Contract.contractID, Equal<ContractBillingSchedule.contractID>>, 
                LeftJoin<Customer, On<Customer.bAccountID, Equal<Contract.customerID>>>>, 
                Where<Contract.isTemplate, Equal<boolFalse>,
                And<Contract.baseType, Equal<Contract.ContractBaseType>>>>), 
                typeof(Contract.contractCD), 
                new System.Type[] { typeof(Contract.contractCD), typeof(Contract.customerID), typeof(Customer.acctName), 
                    typeof(Contract.locationID), typeof(Contract.description), typeof(Contract.status), typeof(Contract.expireDate), 
                    typeof(ContractBillingSchedule.lastDate), typeof(ContractBillingSchedule.nextDate) },
                    DescriptionField = typeof(Contract.description), Filterable = true)]
            [PXUIField(DisplayName = "Contract ID", Visibility = PXUIVisibility.SelectorVisible)]
            [PXFieldDescription]
            
            public virtual int? ContractID
            {
                get { return this._ContractID; }
                set { this._ContractID = value; }

            }

            #endregion contractID

            #region TransitionDate
            public abstract class transitionDate : PX.Data.IBqlField
            {
            }
            protected DateTime? _TransitionDate;
            [PXDBDate()]
            [PXDefault]
            [PXUIField(DisplayName = "Transition Date")]
            public virtual DateTime? TransitionDate
            {
                get
                {
                    return this._TransitionDate;
                }
                set
                {
                    this._TransitionDate = value;
                }
            }
            #endregion TransitionDate
         }

7. We described two properties: contractID and TransitionDate.

8. Now goes time of aspx page at <px:PXFormView> section I described the following:

<px:PXSmartPanel ID="pnlSubstitute" runat="server" AcceptButtonID="PXButtonOK" AutoReload="true" CancelButtonID="PXButtonCancel"
        Caption="Substitute" CaptionVisible="True" DesignView="Content" HideAfterAction="false" Key="SubstituteSettings"
        LoadOnDemand="true" Height="190px" Width="360px" DefaultControlID="edContract">
        <px:PXFormView ID="PXFormView6" runat="server" CaptionVisible="False" DataMember="SubstituteSettings" Width="100%"
            DefaultControlID="edActivationDate" DataSourceID="ds" TabIndex="1400">
            <ContentStyle BackColor="Transparent" BorderStyle="None">
            </ContentStyle>
            <Template>
                <px:PXLayoutRule runat="server" StartColumn="True" LabelsWidth="SM" ControlSize="M" />
                <px:PXSelector runat="server" ID="edContract" DataField="ContractID" CommitChanges="True" Width="130px" />
                <px:PXDateTimeEdit CommitChanges="True" ID="edTransitionDate" runat="server" DataField="TransitionDate" Width="130px" />
                <px:PXLayoutRule runat="server" StartRow="True" />
                <px:PXPanel ID="PXPanel1" runat="server" SkinID="Buttons">
                    <px:PXButton ID="OK" runat="server" DialogResult="OK" Text="OK" />
                    <px:PXButton ID="Cancel" runat="server" DialogResult="Cancel" Text="Cancel" />
                </px:PXPanel>
            </Template>
        </px:PXFormView>
</px:PXSmartPanel>

Few words. AcceptButtonID speak about who plays role of OK button, Caption means title, CaptionVisible means that title will be visible, HideAfterAction means hide or not after action, Key means name of member in extension or graph, DefaultControlID means which control is active by default. Another important detail is DataMember property, which equals to Key.  Then goes layout rules, which I ommit. Then in Template goes selector, and datetime input. 

9. Here how control look like:

Here it is. If you have any comments, wishes, etc, you are welcome to post them

No Comments

Add a Comment

Save Dac Class In Acumatica To Db

Save DAC class in acumatica to DB

Hello everybody,

today I want to note interesting gotcha. Let's say you want to save object to db in Acumatica. You in your code created some DAC item and want to save it to db. And you call Actions.PressSave() method. And you get error. You can get suspection, that maybe you put some wrong data in your DAC class or something like this. 

But the real reason is different, According to T200 Acumatica manual: " You should not invoke the Persist()method on the current graph instance. You can do it only for a graph instance created in a background operation."  It means that you should create instance of Graph, and in that instance call method Persist. 

Here is fragment, which I extracted with the help of reflector:

          ContractMaint instance = PXGraph.CreateInstance<ContractMaint>();
          instance.Clear();
          if (!redirect && !PXAutonumberingInfo.IsDimensionAutonumbered(
(PXGraph)Base, "CONTRACT"))
throw new PXException("Cannot automatically
renew contract when Auto Numbering is off. Please use Renew Contract action on Customer Contracts screen."
); this.RenewExpiring(instance); instance.Save.Press();

Another way to insert some record in db is to use PXDataBase.Insert. Example of usage is the following:

PXDatabase.Insert<APTran>(
                        new PXDataFieldAssign("TranType", PXDbType.NVarChar, apTran.TranType),
                        new PXDataFieldAssign("RefNbr", apTran.RefNbr),
                        new PXDataFieldAssign("ManualPrice", apTran.ManualPrice),
                        new PXDataFieldAssign("LineNbr", apTran.LineNbr));

The first option gives you opportunity to use logic of graph, while second gives you good perfomance.

No Comments

Add a Comment

Principal Component Analysis In Machine Learning

Principal Component Analysis in Machine Learning

Hello everybody,

today I want to note important for me details of Machine Learning. 

So, the first and very important usage of PCA is visualizing data. If you have 10 dimensions, can you visualize those data? If you can I'm happy about you, but I can't. I can imagine only 1, 2, 3 D :). But with principal componenet analysis it's possible to visualize data. 

Second application is reducing memory/disk need to store data. That's quite self-explanatory, to train on 10 000 dimensions and 100 dimensions is different.

Third is speeding up learning algorithm. It's actually related with second.

Another important detail, it's bad idea to use PCA in order to avoid overfitting. Actually everybody who does machine learning knows that decreasing number of features increases chances of overfitting.

No Comments

Add a Comment

How To Override Base Event In Acumatica

How to override base event in Acumatica

Hello everybody,

Imagine following scenario. You have some code in base class, which you need to change. How to do it. For this purpose you can use PXOverride attribute.

See the following code:

public class YourExtension : PXGraphExtension<SomeBasicGraph>
{
   [PXOverride]
   public void MethodForOverriding(string viewName, IEnumerable items)
   {
      // Method body
   }
}

In case which is presented MethodForOverriding of base class will be called. If you want to avoid it, you can add additional argument to the code, and then manipulate how to call it or even omit calling of method from base logic. Look at the following code:

public class YourExtension : PXGraphExtension<SomeBasicGraph>
{
[PXOverride]
public void MethodForOverriding(string viewName, IDictionary keys, IDictionary values, Func<string, IDictionary, IDictionary, int> methodDel)
{
   //some your code
   int res = methodDel(viewName, keys, values);
   //again some of your code. For example you can modify res.
   return res;
}
}

This is very similar to overriding events of DAC classes as mentioned here

No Comments

Add a Comment

Usage Of Base Views In Acumatica

Usage of base views in Acumatica

Hello everybody.

Today I want to write interesting detail, which was strange for me. 

Imagine situation, that you in Extention class want to change some behaviour and want to ask something from view in base graph. You can try to do it with Base.BaseViewName.Cache.Current. And according to my observations it works. But as mentioned in T300 manual To query a data view declared within the base BLC or lower-level extension from the data view delegate, you should redeclare the data view within the BLC extension.

If you want to ask why this copy/paste needed I honestly will tell you: I don't know :)

No Comments

Add a Comment

Event Handlers In Acumatica

Event handlers in Acumatica

Hello everybody,

today I want to share with you how order of event handlers in Acumatica is organized.

Each graph has list of event handlers for each type of manipultaion. Also new declarations of methods can be added to the start or then end of collection, and there are events which are added in the beginning of collection.

According to T300 event handlers which are added to the end of collection:

    • FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)

    • RowSelecting(PXCache sender, PXRowSelectingEventArgs e)

    • RowSelected(PXCache sender, PXRowSelectedEventArgs e)

    • RowInserted(PXCache sender, PXRowInsertedEventArgs e)

    • RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)

    • RowDeleted(PXCache sender, PXRowDeletedEventArgs e)

    • RowPersisted(PXCache sender, PXRowPersistedEventArgs e

Let's say we considered about RowPersisted event. Then the schema will be following:

Base.RowPersisted -> 1st level event handler -> 2nd level event handler. In other words, initially Acumatica code will be executed, and after your code will be executed.

There are also events which has another order which are added to the beginning of the collection:

• FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)

• FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)

• FieldUpdating(PXCache sender, PXFieldUpdatingEventArgs e)

• FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)

• RowInserting(PXCache sender, PXRowInsertingEventArgs e)

• RowUpdating(PXCache sender, PXRowUpdatingEventArgs e)

• RowDeleting(PXCache sender, PXRowDeletingEventArgs e)

• RowPersisting(PXCache sender, PXRowPersistingEventArgs e)

• CommandPreparing(PXCache sender, PXCommandPreparingEventArgs e)

• ExceptionHandling(PXCache sender, PXExceptionHandlingEventArgs e)

From RowPersisting prospective following chain will be executed:

2nd level.RowPersisting  -> 1st level.RowPersisting -> Base.RowPersisting. In other words initially your code will be executed, and only thereafter Acumatica code will be executed and (!!!!) modify your changes to some others. In my practice it was situation, that my changes to RowPersisting was lost because Acumatica basic code removed my code.

Probably you can have question, is there a way to modify this behaviour. What if I want to change order? Yes, it's possible. You just need to use PXAcumaticaEvent template. Look at code below:

protected void DAC_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e, PXRowUpdated del)
{
  //your code can be here 
  if (del != null)
     del(sender, e);
  //or here. Or even in both places
}
Or you can even ignore calling of base code.
protected void DAC_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e, PXRowUpdated del)
{
  //your code can be here 
}
In the second case basic code will not be executed.

With such tricks you can modify behavior in the way you like.

No Comments

Add a Comment

Auto Discovery Mechanism Of Acumatica Extensibility Framework

Auto discovery mechanism of Acumatica Extensibility Framework

Hello everybody,

another interesting notice today. 

Imagine following situation.

1. You have base class. Let it is called GraphX. 

2. In your library you created extentions of this grap: GraphXExt1, GraphXExt2 at the same level. For example like this:

public class GraphXExt1 : PXGraphExtension<GraphX>
{
   protected virtual void ARTran_USRProjectID_FieldDefaulting(PXCache sender, 
PXFieldDefaultingEventArgs e) { } } public class GraphXExt2 : PXGraphExtension<GraphX> { protected virtual void ARTran_USRProjectID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e) { } }

3. Then question, if page will be loaded, which ARTran_USRProjectID_FieldDefaulting will be executed? From GraphXExt1 or from GraphXExt2?

The answer is the last loaded ( !!!!! ). If last loaded by framework will be GraphXExt2 then GraphXExt2 will be the winner. If last loaded will be GraphXExt1 then page will execute ARTran_USRProjectID_FieldDefaulting of GraphXExt1. Acumatica doesn't have any way to configure loading sequence of graphs. It means that it is crazy idea to make changes of the same member in two different graphs.

No Comments

Add a Comment