Tuesday, 10 January 2017

Manual Mass Notifications

Hi All,

Lets imagine scenario where you want to send multiple notifications about multiple documents from the system. It might be quite complicated if you decide to do it manually.
Today I want to show you one trick how you can trigger standard notification on multiple documents at once. For this task we will use Automation Notifications, Custom Field and Generic Inquiry.

My scenario would be to update my customers about quotes that are expiring soon. I want to review them before sending notifications, but do not want to do it one by one.

General idea is - to have a special not visible but editable field that will trigger notification. If we have field, that we can easily update it using Generic Inquiry Mass update operation.

Welcome in the article if you want to see configuration and testing steps.

Friday, 6 January 2017

Useful Web.Config Parameters

Hi All,

Acumatica as standard ASP.NET application stores some configurations in web.config file. Some parameters can be really useful for users and developers.
In this article i want to share with you parameters that really can help you.

Tuesday, 3 January 2017

Append and Replace of DACs Attributes

Hi Everyone.

Today want so share with you some ideas on how you can append, replace or merge attributes on standard Acumatica's data access classes.
Acumatica Framework attributes are used to add common business logic to the application components. Attributes implement business logic by subscribing to events. Each attribute class directly or indirectly derives from the PXEventSubscriberAttribute class. B

Most attributes are added to data access class (DAC) field declarations. There are also attributes that are placed on a DAC declaration, view declarations in a business logic controller (BLC), and the BLC declaration itself. In general there are 4 places where you can define attributes:
  • DAC attributes
    • DAC fields. You can define attributes on property that represents database column.
    • DAC Extension (PXCacheExtension). That extensions are very similar to data access classes itself. You also can define attributes on properties that represents fieds
  • Graph Attributes
    • Graph CacheAttached method. That method has special naming convention to identify DAC and field. That method never be executed by the platform so you should not put any logic there. All attributes are just defined on method itself. Great benefit of defining attributes on CacheAttached method is that you can have different attributes (and logic) in different screens.
    • Graph Extension (PXGraphExtension). Similar to previous one but defined inside graph extension class.

Monday, 19 December 2016

Optimizing Large Import

Hi All

Want to share with you some good approaches to Import a large amount of data.
If you ever tried to import some large set of data from Excel you actually know that it is not as fast as importing data into the SQL table. There are plenty of reasons why it is like this:
  • Data validation
  • Defaulting empty field
  • Running of business logic
  • Data integrity 
  • Updating of referenced data
  • Security tracking
  • Audit 
Of course all these rules have different effects in different modules. It is obvious that GL is much faster than SO Orders. At the same time, AR is faster than SO, but slower than GL.
Also import depends on hardware and database performance.

If you import AR Invoices from Excel you can expect to save about 2 AR Invoices per second.
In this case ideally you can import about 150 000 invoices per day. Actual performance may be different because performance depends on number of invoices and other dictionaries in database. Also this is just saving and does not include release operation that also may take similar amount of time. In addition to the performance we may have problem with errors handling.

What you need to do if you have 1 000 000 invoices to import and little time before go live of a site? It's impractical to use Excel files and import scenarios to do that. It will take too long, and will be very difficult to manage errors and add more advanced data mapping logic.

In this article I want to touch several optimizations tips that can be grouped into few groups:
  • Database Optimizations
  • Import Process Optimization
  • Business Logic Optimization
Lets go through all of them:

Thursday, 15 December 2016

Acumatica and Microsoft Flow

Hi Everyone,

Recently Microsoft has added a new tool to their Office 365- Microsoft Flow
With help of my college - Tim Rodman, we have done some investigations on how it can be used with Acumatica.

I think that in modern internet of services and things services like Microsoft Flow, Azuqua and Zappier might be very useful.

Microsoft flow is most modern here so it does not looks like very mature and stable now. But i belive it is quite promising as Microsoft has enough resources to integrate it with most of Office 365 services. Looking forward to see that progress.

However even now it has some nice things, like HTTP integration where you can call various of web services using REST API.

And really luckily Acumatica already supports REST API.

Monday, 12 December 2016

Enabling Upload from Excel for the Grid

Hi All,

Today I want to share with you a way how to enable upload form excel for custom grid.

Actually this is quite simple -

  1. Step 1 - define PXImportAttribute on data the data view under the grid.

  2. public class CSCalendarMaint : PXGraph<CSCalendarMaint, CSCalendar>
    {
    ...
           [PXImport]
           public PXSelect<CSCalendarExceptions> CSCalendarExceptions;
    ...
    }

  3. Step 2 - enable appropriate Grid Mode (Allow Upload) on the grid properties.
This will enable upload button on the grid action bar with standard functionality.

In some cases, you may want to have more control on the import process. In this case you also may implement optional interface: IPXPrepareItems. This interface should be implemented on processing graph itself.

public interface IPXPrepareItems
{
       bool PrepareImportRow(string viewName, IDictionary keys, IDictionary values);
       void PrepareItems(string viewName, IEnumerable items);
       bool RowImported(string viewName, object row, object oldRow);
       bool RowImporting(string viewName, object row);
}
  • PrepareImportRow - This event will be triggered right before insert record to cache. You can review keys and values that will be assigned to new record.
  • PrepareItems - Used to review items before import, but right now does not execute for performance optimizations.
  • RowImporting - This and next events will be executed only if you decided bypass update of existing records. On that event you can decide what to do with existing record if it was in the database before, for example delete it.
  • RowImported -  Here you can control update operation after insert.
Unfortunately right now there is an issues with declaring PXImport attribute on extension, but this thing will be fixed soon and you will have a easy way to import everything instead of typing.

Have a nice development!

Wednesday, 7 December 2016

Using Colors in Acumatica

Hi All,

Today I want to share with one way how you can highlight some Acumatica rows or data with colors or other text styles.

Monday, 5 December 2016

Custom Formula for ACH/GIRO Providers

Hi All,

In the previous article about custom payment providers i have mentioned that Schema file supports several build-in formulas, like:
  • Count - Count of details or nested groups in group
  • TotalCount -  Total lines in all nested groups
  • BlockCount - Count of internal blocks including adjustments for fixed structure
  • CountOneBased -  CountField  + 1. Required if you need calculate header or footer with details
  • TotalCountOneBased - TotalCountField +1. Required if you need calculate header or footer with details
You also can add more formulas there. For example if you want to have Count that will calculate header and footer together with details you may need TotalCountTwoBased formula.

Please check this code snippet for more details:

Have a nice development! 

Thursday, 1 December 2016

Client Events using JavaScript

Hi All,

Today I want to share with you one way how you can add some client validations/calculation using JavaScript right in the browser with no accessing server data.
In general i would suggest you to not do any complex calculations on client side and always use server for all data manipulations. However in some specific situations this approach may save a lot of processing time because client events may do calculations right in the browser.
Also note that client logic will be available only for browser users and will not be triggered from web services API and Mobile application.

The scenario that i want to do is quite simple - trigger the code after the value changes in some controls and validate/calculate its value. This example is designed for demonstrating purpose only so I would like just to show a notification box with new value when someone change GL Batch description.
As a much better example of client events may be a playing of sound on button/control click. Really good explanation and example example is provided on Stack Overflow.

Customization
To add required validation lets complete following steps:

Monday, 28 November 2016

PXUIEnabled and PXUIRequired Attributes

Hi All,

If you developing something on Acumatica xRP platform you know that changing of the UI fields visibility should be done through PXUIFieldAttribute on the RowSelected event.

This works perfect on small screens with limited number of controls. But most of ERP screens are not really small. So most probably you already saw such types of code on the RowSelected in SOOrderEntry graph and many others.

Not nice and really hard to support.
Luckily now we have a different way to do it:

  • PXUIEnabled - based on provided BQL conditions can automatically change UIFieldAttribute Enabled property.
  • PXUIRequired - based on provided BQL condition can automatically change PXDefaultAttribute PersistingCheck property.
  • PXUIVerify - based on provided BQL condition can automatically change validate that new value meets provided conditions. Also can trigger validation on update of dependent fields,

Usage of PXUIEnabled:

#region isActive
public abstract class isActive : PX.Data.IBqlField
{
}
[PXDBBool]
[PXDefault(true)]
[PXUIEnabled(typeof(Where<isFinancial, NotEqual<True>>))]
[PXUIField(DisplayName = "Active", Visibility = PXUIVisibility.SelectorVisible)]
public virtual Boolean? IsActive { get; set; }
#endregion


Usage of PXUIVerify:
#region TimeBillable
public abstract class timeBillable : IBqlField { }
[PXDBInt]
[PXTimeList]
[PXDefault(0, PersistingCheck = PXPersistingCheck.Nothing)]
[PXFormula(typeof(
       Switch<Case<Where<isBillable, Equal<True>>, timeSpent,
              Case<Where<isBillable, Equal<False>>, int0>>,
              timeBillable>))]
[PXUIField(DisplayName = "Billable Time", FieldClass = "BILLABLE")]
[PXUIVerify(typeof(Where<timeSpent, IsNull,
       Or<timeBillable, IsNull,
              Or<timeSpent, GreaterEqual<timeBillable>>>>),
PXErrorLevel.Error, Messages.BillableTimeCannotBeGreaterThanTimeSpent)]
[PXUIVerify(typeof(Where<isBillable, NotEqual<True>,
       Or<timeBillable, NotEqual<int0>>>),
PXErrorLevel.Error, Messages.BillableTimeMustBeOtherThanZero,
       CheckOnInserted = false, CheckOnVerify = false)]
public virtual int? TimeBillable { get; set; }

#endregion

Have a nice development!