Friday, 22 June 2018

Acumatica 6-tiers Web Architecture

Hi All,

Recently got a question about Acumatica web architecture and tires. To answer it I have prepared slide that I would like to share with you now:

Acumatica Web Architecture:
Acumatica 6-tiers Web Architecture

Wednesday, 30 May 2018

Use Split Container from Customization Browser

Hi Everyone,

You may know that in Acumatica you can put several large containers (like grids and forms) together. But to controls or optimize space usage on small screen Acumatica uses special Split Container control.
Acumatica Split Container
Basically this is the panel that you can drag and drop to reallocate space used by nested controls.

To handle it Acumatica ASPX markup has special element:
<px:PXSplitContainer runat="server" ID="PXSplitContainer1" Orientation="Horizontal">
  <AutoSize Enabled="true" Container="Window" />
  <Template1> </Template1>
  <Template2> </Template2>
</px:PXSplitContainer>

Wednesday, 23 May 2018

Toggle List as Entry Point

Hi All,

List as entry point is very nice feature that allows yoг to see multiple documents together. However in some cases you may want to get document faster and eliminate unnecessary clicks.
Acumatica List As Entry Point
Luckily Acumatica gives your options to choose if you want to enable it or now. You can control this for Modern UI and Classic UI separately.  Just go to screen Lists as Entry Points (SM208500)

In the end to make my life few seconds easier I have created a simple button that can toggle On and Off lists as entry point wherever I need them or not.

Have a easy UI.

Friday, 4 May 2018

Auto-Numbering Customization

Hi All,

In Acumatica PX.Objects.CS.AutoNumberAttribute is responsible for almost all auto-numbering. However sometimes you may want to have control on it. For example change sequence depend on conditions or add specific numbers related to vendor or customer.
These things quite easy to do with customization. Here I'm going to show you 2 scenarios:
  • How to change numbering sequence
  • How to change new number

Thursday, 19 April 2018

Resort grid rows with Drag & Drop

Hi Everyone,

In Acumatica 2018R1 we have a new cool feature to drag and drops rows of the grid to resort them.
As you can see sorting is still based on database column (In my case it is Sort Order) but Acumatica can automatically reorder all rows based position you dropped it.
This is just a first version so still have some limitations (like it is still not fully works with extensions for existing DACs), but I really like we can  bring new and very friendly user experience to ERP.

How to implement it in own code? To have this feature you need to change several things in your Graph, DAC and Page:

Graph
In Graph we need to replace your normal PXSelect with new PXOrderedSelect. This data view has all logic to update sorting upon drop of the row.

public PXOrderedSelect<AAMasterAADetail
      Where<AADetail.masterIDEqual<Current<AAMaster.masterID>>>
      OrderBy<Asc<AADetail.masterIDAsc<AADetail.sortOrder>>>> DetailsView;

Also PXOrderedSelect will add 2 new buttons (PastRow and ResetOrder) to graph actions that you may need to hide from Datasource actions later in the page.

DAC
In the DAC you need to implement interface ISortOrder, that requires to have LineNbr and SortOrder properties.
  public class AADetail IBqlTableISortOrder
  {
    #region LineNbr
    [PXDBInt(IsKey true)]
    [PXUIField(DisplayName "Line Nbr"Visible false)]
    [PXLineNbr(typeof(AAMaster.masterCntr))]
    public virtual intLineNbr getset}
    public abstract class lineNbr IBqlField }
    #endregion
    #region SortOrder
    [PXDBInt()]
    [PXUIField(DisplayName "Sort Order"Visible falseEnabled false)]
    public virtual intSortOrder getset}
    public abstract class sortOrder IBqlField }
    #endregion
  }

ASPX Page
In the page you need to do several things: hide actions, allow grid Drag&Drop and configure postback.

Here in data-source you need to hide commands:
<px:PXDataSource ... >
 <CallbackCommands>
  <px:PXDSCallbackCommand Name="PasteLine" Visible="False" 
   DependOnGrid="grid" CommitChanges="true" />
  <px:PXDSCallbackCommand Name="ResetOrder" Visible="False" 
   DependOnGrid="grid" CommitChanges="true" />
 </CallbackCommands>
</px:PXDataSource>

Here in grid you need to sync grid position, allow drag and drop and link PasteCommand with action.
<px:PXGrid SyncPosition="True" ID="grid" ... >
 <Mode InitNewRow="True" AllowDragRows="True" ></Mode>
 <CallbackCommands PasteCommand="PasteLine">
  <Save PostData="Container" />
 </CallbackCommands>
</px:PXGrid>

After this drag and drop should work as it shown on the grid before!

Hope it is helpful for you! Have a nice development!

Thursday, 12 April 2018

PXSelector and DirtyRead

Hi Everyone,

Want to speak today about Dirty Read property of selector.
Base explanation you can find in Acumatica API reference. How ever this one is very basic, so let me try to share with you real case.

You may know about Readonly vs Merged data retrial from DataView. Basically if you use PXSelectReadonly data-view it will always return data only stored in database. If you use standard data-view like PXSelect Acumatica will get data from DB and than merge it with unsaved data from cache.
This is fully applicable for data-views (PXSelect, PXSelectReadonly) and selectors as well. When you define PXSelectorAttribute than it will be always read-only by default. However you can make it not read-only using DirtyRead = true parameter.

[PXSelector(typeof(Users.pKID), SubstituteKey = typeof(Users.username), DirtyRead = true)]
protected virtual void Contact_UserID_CacheAttached(PXCache cache)

Why you may need it? Lets imagine you have 2 DACs that are refers each other thought text key with PXSelectorAttribute.
In this case if you insert new record for DAC 1 and DAC 2 simultaneously you will may have a problem with selector as record of DAC 1 is not yet saved and selector will throw Item not Found exception.
Here exactly DirtyRead comes to help us - in this scenrarion selector with DirtyRead=true will select DAC1 from database, merge it with cache (new inserted record) and no error will be triggered.

In the example of PXSelector above Acumatica allows to link Contact with just created use account. So that means that if you create user on the fly with code and it is not saved but needs to be linked with contact - DirtyRead helps us.

Profit! Hope it helps!



Monday, 2 April 2018

Schedule Database Maintenace

Hi All,

Just want to share one screenshot guide on how to schedule a database maintenance:
Acumatica Database Maintenance

Have a smooth maintenance!

Tuesday, 20 March 2018

Multi-Line TextEdit control

Hi Everyone,

In case you need to store rather big text you may need to use multi-line text edits. Here I would like to share with you example based on Address Line on Customer Form.

Multi line just a property of the text edit so if you just change mode of control in Customization browser you will be able to use enter in control already.
As soon as you publish customization control will add cut angle what you can use to control its size with mouse:
If you also set height property of control for example to “100px” size will be extended in UI by default:
Important to note that if changing of control mode does not remove filed length restrictions, so you also need to make sure that DAC and DB field has enough allowed length to accommodate all lines.

Have a nice development!

Friday, 16 March 2018

Extend Address Line length

Hi Everyone,

Extending of field length in Acumatica is not a trivial task, so here I want to publish guidance on how I usually do that.

To extend field we need to do 2 things:
  • Extend allowed length in DAC attribute
  • Extend length of Database Column
Welcome under the cut for more details

Tuesday, 13 March 2018

Another process has added/updated/deleted the '{0}' record. Your changes will be lost.

Hi There,

Today want to discuss with you how what is ” Another process has added/updated/deleted” error and how to investigate/fix it.

Why it happens?
Let’s start with error understanding. Actually, this error comes from potential differences between user copy of data and actuals in database.
Before I jump into details I want to remind you few architectural points about Acumatica:
  • Acumatica commits records one by one in most cases. For several records update statement will be executed multiple times.
  • Also Acumatica stores the data needed to be save inside in-memory user specific cache. So it is possible that 2 users may have several versions of the same record with different values that is not yet saved.
  • Saving is always done in transaction.
Back to our exception - there are 2 possible reasons for this error:
  • Record was not found in database during search by keys
  • Record was modified and has changed timestamp

Monday, 12 March 2018

PXProjection – SQL Views using BQL

Hi Everyone,

Occasionally I get question from partners related:
  • Can we Join several tables with possibility to update them all? You know that Joined tables in Acumatica are read-only and you cannot update fields there
  • Can we create/use SQL-like views in Acumatica?
  • How can I join grouped (statistical) view to the DAC?
The answer to all these questions is yes you can do it. But answer on how to do that is not so simple. Obviously the most strait forward way is to create an SQL view and generate a DAC based on it. But this way does not solve point number 1 – SQL view is read-only and does not allow to update tables inside.

The more advanced way is to use Acumatica Framework. Basically, you need to use special PXProjection attribute. PXProjection is some sort of the SQL-like view that is done with BQL with some advanced functionality.

Data Selection though Projection.
To use it you need to complete few steps:
  • Create new DAC that will represent view. This DAC may have less columns than you have in DACs you will select later. So just define fields you need. In the end it will help a bit with select performance.
  • You need to define PXProjectionAttribute on this DAC. For PXProjection constructor you should provide BQL command that will define what tables you want to select. You may use all possible commands of BQL (Join, Where, GroupBy, OrderBy).
[PXProjection(typeof(Select5<ARHistory,
        InnerJoin<FinPeriod,
                On<FinPeriod.finPeriodIDGreaterEqual<ARHistory.finPeriodID>>>,
        Aggregate<GroupBy<ARHistory.customerID>>))]
public class ARHistoryByPeriod : PX.Data.IBqlTable { … }
  • You need to specify BQLField property for all database related fields. BQLField is inherited from PXDBFieldAttribute, so all DB field attributes (PXDBString, PXDBBool, PXDBInt and so on) have it inside plus most of Aggregate attributes (CustomerAttribute, Account, FinPeriodID). BQL Field is needed to identify from what table (out of joined in BQL above) this particular field should be taken. This configuration cannot be automatic as different tables may have fields with same names. Also do not forget to define correct keys inside your projection DAC.
[FinPeriodID(IsKey = true, BqlField = typeof(FinPeriod.finPeriodID))]
public virtual String FinPeriodID { … }

That is all! Now you can use this DAC inside PXSelects, Reports and Generic Inquires.

PXSelectJoin<ARHistoryByPeriod,
        InnerJoin<Customer,
                On<Customer.bAccountIDEqual<ARHistoryByPeriod.customerID>>,
        LeftJoin<LastRevaluation,
                On<ARHistoryByPeriod.customerIDEqual<LastRevaluation.customerID>,
                And<ARHistoryByPeriod.branchIDEqual<LastRevaluation.branchID>,
                And<ARHistoryByPeriod.accountIDEqual<LastRevaluation.accountID>,
>>>>>>;

You can read more about PXProjection Attribute in Acumatica Help Files.

Data Modification though Projection. Another important thing that is supported by PXProjection is saving changes direct to database. As you have defined DACs in your projection definition, Acumatica knows keys of each record (from original DAC) and can use it to track changes and update values back to correct record of database. But please note that this feature is not available for projections with Group By clause as than keys will be lost with aggregation.

To activate it just put Persistent = true inside PXProjection constructor.

[PXProjection(typeof(Select<TaxTran,
        Where<TaxTran.module,Equal<BatchModule.moduleAP>>>), Persistent = true)]
public partial class APTaxTran : TaxTran { … }

One more example of good editable projection usage:

[PXProjection(typeof(Select2<ARRegister
        InnerJoin<ARInvoice
                 On<ARInvoice.docTypeEqual<ARRegister.docType>, 
                         And<ARInvoice.refNbrEqual<ARRegister.refNbr>>>, 
        InnerJoin<ARPayment
                 On<ARPayment.docTypeEqual<ARRegister.docType>,
                         And<ARPayment.refNbrEqual<ARRegister.refNbr>>>>>,
        Where<ARRegister.docTypeEqual<ARDocType.cashSale>, 
                 Or<ARRegister.docTypeEqual<ARDocType.cashReturn>>>>),
Persistent = true)]
public class ARCashSale : ARRegister { .. }

Have a nice development!

Monday, 5 March 2018

Keep Multiple Acumatica Installers Locally

Hi Everyone,

When you install Acumatica from AcumaticaERPInstall.msi you actually get program that we call Acumatica Configuration Wizard. Than you can use Wizard to install as many as you wish Acumatica Instances. So Acumatica installation is done thought 2 steps:
  1. Configuration Wizard installation via MSI file
  2. Acumatica ERP Instance deployment via Acumatica Configuration Wizard.
Today want to share with you nice trick on how to have multiple Acumatica Configuration Wizards at the same time.

You most probably know that you cannot install several versions of Acumatica Configurations Wizards on machine at the same time. That is some sort of limitation from Microsoft Windows that does not allow to have one application installed multiple times. However Acumatica instances are there untouched with the version you installed until you have updated it with wizard explicitly.
So if you have Acumatica 2017 on your machine and you want to test Acumatica 2018 than you have to download new installer (AcumaticaERPInstall.msi) and update/replace old version with new one. When you do this you suddenly understand that you cannot install/maintain Acumatica instance of previous version as wizard can only update it.

So how to overcome it? There are 2 ways to do this:

Uninstall new version of Acumatica configuration wizard and install old one. As I have mentioned already this is totally save operation. Uninstallation of wizard will not touch any instances or databases that you can easily use even without wizard. To speed up this you even can write a batch script that can do this in unattended mode but it is still slow and not really nice.

Copy Wizard to Separate Folder and use it from copy any time. Acumatica Configuration Wizard is actually standalone and portable program that can be used without installation. Installation is really need to make it easier for end users. But if you are power user and you know how to use it you can use that nice hidden feature of wizard.

There are few folders that you need to be accessible for Installer:

  • Data - Main folder where Acumatica Configuration Wizard executable are
  • Database - All database related scripts are here.
  • Files - the original copy of Acuamtica instance. During installation wizard copies it to the instance folder
  • Portal - is used only during portal installation
That is actually it. If you copy these 4 folders in separate directory you will be able to user wizard even if you uninstall Acumatica or upgrade it to the new version.

Acumatica Configuration Wizard Copy

To Launch Acumatica Configuration wizard you can go to Data folder and click on AcumaticaConfig.exe. It will lunch wizard as usual.
Acumatica Configuration Wizard

Have a nice installation!

Monday, 26 February 2018

Apply Customization to all Graphs

Hi All,

Today want to share with you one tip how can you add customization to all graphs at once.

You know that you can define graph extension with specific graph – PXGraphExtension<PX.Objects.GL.JournalEntry>. However, all graphs are inherited from one base class ether PXGraph<TGraph> or PXGraph<TGraph, TPrimaryView>. In that case PXGraph is normal class and can be used as standalone object.
In terms of our customizations that means that we can create an extension for parent PXGraph and it will be used with any graph in the system automatically.

Here we have an example how can you add a special setup to any graph in Acumatica. Please note that we are using Initialize method instead of constructor because dataviews are not yet initialized when extension constructor is called.

Saturday, 24 February 2018

Custom Code on AP Invoice Release

Hi Everyone,

What to share example with you how to call custom code during AP invoice release. In general process for AP is very similar to what is described in Acumatica T300 Customization Guide in Lesson 7: Customizing the Logic of the Release Action.

Here you also need to find the best place where you can put your custom code and than write it there. Similar to guide above the best place is actually persisting method of APReleaseProcess graph.
Lets check check how to investigate code first and when write a logic.

Monday, 19 February 2018

Custom Image on Acumatica Form

Hi All,

Want to share with you way how can you add custom Image on Acumatica form.
Acumatica custom Image
To do that you can use PXImage control. In the ImageUrl you can add physical path to image on the file system.

<px:PXImage runat="server" ImageUrl ="~/Icons/login_logo.png"  />
Acumatica PXImage

This is static image and not linked with any data view or dac, so if you need to change images dynamically you have to write logic in the code behind file however it is not recommended way by Acumatica standards.

Have a nice development!

Tuesday, 13 February 2018

Cases Escalation

Hi All,

Have you faced the need of escalation process in Acumatica CRM?
In general it is not so complicated to do with work-groups - when you need escalation you just change work-group. Support engineers can monitor a queue (or get a notifications) and work on case.
But here we have quite some manual processes: add escalation note, change status, change work-group.

However we can easily solve it with customization. Let me show you the scenario where you have 2 (or more) buttons: Escalate to L2, Escalate to L3 and so on.
Acumatica Case Escalation Buttons
Each button will show you pop-up form that you need to feel before escalation and do other automation. Pop-up can be pre-filled with text template from Notification Templates. Technically Escalation pop-up is a separate page that is shown as a dialog from code.
Acumatica Case Escalation Buttons
Upon save, our customization will add note to case activities and change a work-group.
Acumatica Case Escalation Automation
Work-group assigned and Template for escalations can be configured on Customer Management preferences.
Acumatica Case Escalation Setup


Project Sources: https://github.com/smarenich/Escalations
Pre-Compiled Project: Escalations.zip

You can easily take project shared and add there own logic and more escalation rules.

Have a nice development!

Wednesday, 31 January 2018

Add new Value to Combo-Box via Automation Steps

Hi All,

Lets assume that you need to add a new value to combo-box control without any dependent logic. And you do not want to do this with Customization as you do not know that. And with Acumatica it is really easy to do.

Lets check an example where you need to add new source for leads. "Source" is just for informational purpose and does not have depended logic (in other words there is no different business logic depend on selected value). So that means that if we add a new value there we do not break anything.
If your combo-box has logic associated (fields enabled disabled / different calculations) than you may need to consider code customization instead of approach described here.
Acumatica Leads

Ok, so if the above conditions is met, we can proceed with adding values thought Automation Steps. "Automation Steps" is automation configuration in Acumatica that allows you to dynamically disable enable controls, add buttons, combo-box values depend on "step" where your document is currently in. For example if document is open you can print report, but if it is closed you cannot.

Here with Automation Steps we can add non-programmatic customization for some fields. Lets add source field for step Open. For our task step is not important as you can add value on any step, but for other tasks you may need to add fields/buttons on every step where you want to use it.
Acumatica Automation Steps

 Than you can use "Combo-Box Values" button to see and add there your own values.
Acumatica Automation Steps with ComboBox

As soon as you save the step you can refresh Leads screen and find a new value there.
Acumatica Leads with Custom Source

Hope it helps and have an easy configuration!

Tuesday, 16 January 2018

Show/Hide Grids on the Fly

Hi Everyone,

Sometimes you need to show user interface differently depend on parameters selected. Here I want to show you an approach where you can show different grids depend on parameters selected in filter.

You may need different grids in the following cases:
  • If have different data access classes (tables) to show.
  • If you need to have different grids layout depend on parameters.
  • If you  need to to have different columns configurations.

Friday, 12 January 2018

Multi-Select Selector

Hi There,

Want to share with you hidden way to add a multi-select Selector control to have better filters.
Acumatica Multi Selector

There is a special UI Control px:PXMultiSelector that allows you to select multiple values in the same field. Values will be stored in the field with Semicolon Separator. For example in the field like shown above we will have following value: ACTUAL; BUDGET
Acumatica Multi Selector Value

To add such control you need to do following:
  1. Define a selector on the DAC field. Please note that you should disable Validate value, as selector will try to search combined value in DB and fails with error.
    1. [PXSelector(typeof(Ledger.ledgerCD), ValidateValue = false)]
  2. Second step will be UI control definition. Note that there is no such control in the list of available controls, so you have to edit ASPX directly, but it is easy to replace PXSelector with PXMultiSelector. Do not forget Commit changes if you need to filter by this field. 
    1. <px:PXMultiSelector runat="server" DataField="Ledger" ID="CstPXSelector4" CommitChanges="True" ></px:PXMultiSelector>
Multi-Value selector will be good with new In<> Bql operator in Acumatica 2017 R2


Have a nice development!


Monday, 8 January 2018

Generate IN Receipt from the Code

Hi All,

In my experience I have quite a lot of questions like - how to create a document on the fly.
The answer is rather simple - we need to use the same objects as user interface and emulate user interface behavior.
  • As the main object that contains a business logic and validation is Grpah, we need to create it from the code and use for calling actions and pushing data.
    • INReceiptEntry graph = PXGraph.CreateInstance<INReceiptEntry>()
  • To create a new object we can use PXCache.
    • INRegister header = (INRegister)graph.CurrentDocument.Cache.CreateInstance();
  • Every container control form UI is linked with Data View that is linked with DACs and tables. As you may know from Acumatica Platform Achitecture UI sends just 4 commends to the server logic (Insert, Update, Delete, Select). So in our code we need to use corresponding data views and call appropriate commands with data provided.
    • header = graph.CurrentDocument.Insert(header);
  • Acumatica uses Events triggered from UI we need to emulate it with calling appropriate commands of Data Views when necessary. For example if you choose Inventory Item, Acumatica defaults some values. We need to emulate this call to server logic with Update command.
    • tran.InventoryID = 691; tran = graph.transactions.Update(tran);
  • We also need follow the flow how user creates a record. For example we need to fill document first before entering transactions.
So basically that is it.

Please check my simple example extension where I create a Inventory Receipt from button on Sales Orders screen.
Acumatica Create Receipt


Code:

Have nice development!