LSSelect view in Acumatica

Hi all. Today I want to told you about how to override Split Lines on Acumatica screens:

This pop-up used on different screens like SO302000 or S0301000…

Overriding the view in 21 R1 and older versions look like this:

Imagine situation that you want to control this functionality or make automatic allocation on some action. The problem I encountered was that I could not fully override lsselect.

 More precisely, I overloaded but I could not disable the execution of basic logic.

For a sample my task was to make an automatic allocation when user click on save the order and control qty’s on the grid.

After several overloads, I could not control this grid. So I decided to adjust to the basic logic.

Here is a piece of code that I use:

private void SetupAllocation(SOOrderEntry sooRderEntry, SOLine line)
{
 
    SOOrderExt currSoOrderExt = sooRderEntry.Document.Current
        .GetExtension<SOOrderExt>();
    Base.Transactions.Current = line;
 
    foreach (SOLineSplit split in Base.splits.Select())
    {
        // some conditions
        if (split.Completed == false && split.IsAllocated == false)
        {
            SOLineSplit oldLine = PXCache<SOLineSplit>.CreateCopy(split);
 
            decimaldiffQty = 0m;
 
            Base.splits.Cache.RaiseRowUpdated(split, oldLine);
            //qty that we want to allocate
            split.Qty = Base.Transactions.Current.OpenQty;
            split.IsAllocated = true;
            Base.splits.Cache.RaiseRowUpdated(split, oldLine);
            Base.splits.Update(split);
 
 
            // diffQty = //here you can set your value 
 
            Base.splits.Cache.RaiseRowUpdated(split, oldLine);
 
            split.Qty = //first value
                split.IsAllocated = true;
 
            Base.splits.Update(split);
            //if you want to insert new row into the grid     
            if (diffQty > 0)
            {
                SOLineSplit newsplit = new SOLineSplit();
 
                newsplit.LineNbr = split.LineNbr;
                newsplit.Qty = diffQty;
                newsplit.IsAllocated = false;
                Base.splits.Insert(newsplit);
            }
        }
    }
}

 I did something like that. And now I can control automatic or manual allocation also I can control how much qty allocate.

But in the 21R2 version Acumatica changed the code and now for overriding you should do like this:

And I am sure that now will be easier to override and control this panel. In the near future I will do more tests and share the result.

 

 

ABC-XYZ analysis for laymen

Hello everybody,

In this post, I’m going to explain ABC-XYZ analysis and why your company should bother about it. Also, I hope after reading this blog post you’ll understand why big companies, at least at some stage, use ABC-XYZ analysis.

So, first of all, ABC-XYZ analysis is a tool that allows you to classify your products into two main groups:

  1. ABC
  2. XYZ

ABC metrics tell you about the volume of sales. Where A – best sellers, B in between sellers, C – worst sellers

XYZ metrics tell you about the regularity of sales. Where X – stands for regular sellers, Y stands for more or less regular sellers, and Z are irregular sellers.

After I’ve read this explanation, I still was puzzled; and for me, it still wasn’t clear what ABC-XYZ is all about. But please bear with me for few more minutes, and I’ll explain ABC-XYZ via example, and hopefully, everything will be clear.

Imagine that you are an owner of a bakery. And your bakery produces three kinds of products:

  1. Bread

2. Biscuit

3. Wedding cake

And now the question is: what product will be sold in the highest quantities and regularities?

Most probably, you’ll agree that bread will be the winner in the category of quantity and regularity.

What product will be number two by regularity? Definitely a biscuit. And what will be the number three in quantity and regularity? Wedding cake.

If to look from the perspective of ABC-XYZ, the break will belong to A category by quantity and X category by regularity. Biscuit will belong to B category by quantity and Y category by regularity. And wedding cake will belong to C category by quantity and Z category by regularity.

So far, so good?

But imagine that your company sells not bread, but, for example, GPS trackers, toys, furniture, or something else. How can you figure out what bread of your company is? And what about biscuit and wedding cake? What if you have not three products, but let’s say 100. Which of these products belong to A, B, C. And which belong to X, Y, Z? How could you track/notice cases when bread from A becomes C. Or when wedding cake from Z moves to X by regularity? All of this may be accomplished with the help of our ABC-XYZ analysis and advanced ABC-XYZ profit margin analysis.

 

ConsentDate has been expirated in Acumatica

Today I will tell you how to fix the import error for CROpportunity "No consent date has been specified".

In order to import CROpportunity you need to create DataProvider and ImportScenario

Data Provider (SM206015)

Import Scenario (SM206025)

Now you have to go to the Import by Scenario (SM206036) screen and do the Import data.

After the successful import, you can see that a new Opportunity was created, but the Contact and Owner fields were not filled in.

This can easily be corrected by making changes to the Import scenario for

  • «Contact» - «ContactID!DisplayName»
  • «Owner» - «OwnerID!DisplayName»

Let's repeat the import on the page Import by Scenario (SM206036)

Import result as an example of one of the records

Good luck with your imports!

 

Good luck with your imports.

 

 

 

 

Display values from 3-rd party API in Acumatica

Good day everyone!

Today I want to share with you one experience with dynamic (virtual) data in Acumatica.

Imagine that you want to have a custom virtual view in Acumatica, and use it to get and update records in the cache.

It can be a lot of different situations such as getting data from a file and putting it into view or getting data from another view, updating the records and so on.

For example, let take a popular screen Sales Order (SO301000).

On updating the Document Details (SOLine) row, I want to have a custom control Availability of selected Item.

What does it look like in the code?

I created a SOOrderEntryExt graph extension and my virtual DAC:

 Snippet

[PXVirtual]

 

public class CustomVirtualDAC : IBqlTable
{
 
    #region InventoryID
    public abstract class inventoryID : PX.Data.BQL.BqlInt.Field<inventoryID> { }
 
    [PXInt(IsKey = true)]
    [PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
    [PXUIField(DisplayName = "InventoryID")]
    public virtual int? InventoryID
    {
        get;
        set;
    }
    #endregion
 
    #region SiteID
    public abstract class siteID : PX.Data.BQL.BqlInt.Field<siteID> { }
 
    [PXInt(IsKey = true)]
    [PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
    [PXUIField(DisplayName = "SiteID")]
    public virtual int? SiteID
    {
        get;
        set;
    }
    #endregion
 
    #region LocationID
    public abstract class locationID : PX.Data.BQL.BqlInt.Field<locationID> { }
    [PXInt(IsKey = true)]
    [PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
    [PXUIField(DisplayName = "LocationID")]
    public virtual int? LocationID
    {
        get;
        set;
    }
    #endregion
 
    #region AvailQty
    public abstract class availQty : PX.Data.BQL.BqlDecimal.Field<availQty> { }
    [PXDecimal(2)]
    [PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
    [PXUIField(DisplayName = "AvailQty")]
    public virtual decimal? AvailQty { getset; }
    #endregion
}

 After in SOOrderEntryExt I added my view and event:

 

public SelectFrom<CustomVirtualDAC>.View CustomVirtualView;
 
public virtual void _(Events.RowUpdated<SOLine> e)
{
    SOLine oldRow = e.OldRow as SOLine;
    SOLine row = e.Row as SOLine;
    CustomVirtualDAC currVirtualRez = null;
 
    if (row != null)
    {
        currVirtualRez = ReturnVirtualDACRez(row.InventoryID,
            row.SiteID, row.LocationID);
 
        if (row.OrderQty > oldRow.OrderQty)
        {
            //do what needed
            currVirtualRez.AvailQty -= row.OrderQty - oldRow.OrderQty;
            CustomVirtualView.Update(currVirtualRez);
        }
    }
 
}

 And one more method where I can return the needed row or add if it does not exists:

 

public CustomVirtualDAC ReturnVirtualDACRez(intinventoryIDintsiteIDintlocationID)
{
    CustomVirtualDAC currVirtualRez = null;
 
    foreach (CustomVirtualDAC mkinItemStatus in
        CustomVirtualView.Select())
    {
        if (mkinItemStatus.InventoryID == inventoryID && mkinItemStatus.SiteID == siteID && mkinItemStatus.LocationID == locationID)
        {
            currVirtualRez = mkinItemStatus;
        }
    }
 
    if (currVirtualRez == null)
    {
 
        InventorySummaryEnq tempGraph = PXGraph.CreateInstance<InventorySummaryEnq>();
        tempGraph.Filter.Current.InventoryID = inventoryID;
        tempGraph.Filter.Current.SiteID = siteID;
        tempGraph.Filter.Cache.Update(tempGraph.Filter.Current);
        foreach (InventorySummaryEnquiryResult record in tempGraph.ISERecords.Select())
        {
            CustomVirtualDAC newVirtualRez = new CustomVirtualDAC();
 
            newVirtualRez.InventoryID = record.InventoryID;
            newVirtualRez.SiteID = record?.SiteID;
            newVirtualRez.LocationID = record?.LocationID;
            newVirtualRez.AvailQty = record?.QtyAvail;
 
            CustomVirtualView.Insert(newVirtualRez);
        }
 
    }
 
    return currVirtualRez;
}

 

Everything seems ready and should work.But not. I receive error message Incorrect syntax near the keyword 'OPTION':

 

This is because Aсumatiсa is still trying to extract data from a table that does not exist. And none of the attributes such as [PXCopyPasteHiddenView] or [PXVirtualDAC] does not help.

To resolve this problem, you must implement a Dataview delegate when using a Virtual DAC.

So, in your graph extension you must add a dataview delegate to return the records that you need:

protected virtual IEnumerable AvailibilityView()

      {

       //fetch your records

         return your records;

      }

In my specific case, I must implement something like that:

 

public virtual IEnumerable customVirtualView()
{
    List<CustomVirtualDAClistRez = new List<CustomVirtualDAC>();
 
    foreach (CustomVirtualDAC line in CustomVirtualView.Cache.Inserted)
    {
        listRez.Add(line);
    }
 
    foreach (CustomVirtualDAC line in CustomVirtualView.Cache.Updated)
    {
        listRez.Add(line);
    }
    return listRez;
}

 Because I can`t call CustomVirtualView.Select() in the delegate because this will loop the code.

Now it will work.

 

Summary

In case if you need to read data from some 3-rd party source, and display it on the screen, then you have two ways:

1. Create useless table in Acumatica data base

2. Follow technique described in this article. 

 

 

 

 

 

 

 

 

 

 

 

Export from Acumatica to Excel via export scenario

Hi everybody,

today I want to leave a note on how to export from Acumatica to Excel.

To export data to excel, you need to go to the "Data Providers" page, screen SM206015,

then create a provider, fill in such fields as Name, Provider Type (in the case of Excel, select PX.DataSync.ExcelSYProvider), after which you need to add a file for export (where we we will display the data), and add it to Files,

then go to the SCHEMA tab, and fill in the correspondence of the fields into which we will export the data, 

we can click on the FILL SCHEMA OBJECTS / FILL SCHEMA FIELDS button in order to load ready-made fields with the previously loaded tables, or write your own, pay attention, the Active checkbox must be pressed.

After all this, don't forget to save your data.

 

 

Then we go to the "Export Scenarios" page, screen SM207025,

 

How To Show Tab And Grid Always In Acumatica

Hi everybody,

today want to mention following use case:

1. Created Tab or Grid or element in Splitter

2. If View returns zero values

3. Element created at step 1 doesn't appear

How to deal with that?

Set AllowAutoHide to false, and Visible to true and element will not hide automatically.

How To Find Pxprojection Which Has Soorder In The Next Line In Acumatica Source Code

 

Hello everybody,

today I want to speak about very useful feature in Visual Studio.

Sometime you may need some kind of source of inspiration from Acumatica source code. But quite often that source of inspiration have text, which is scattered over multiple lines of code.

For example, you want to find file which has PXProjection text in one line, and word SOOrder in the next line. How to make such a search? Window below appears once you click on Ctrl + Shift + F:

with help of .*\r?\n.* you can make search over multiple files. Take a note of what Visual Studio showed to me in output results once I've clicked on Find All:

and then, you can double click on any of those lines, and make sure, that you found something, that is PXProjection, with SOOrder in some of the next lines:

Summary

With such simple technique you can easily hunt for any lines of code in Acumatica framework, and enhance your search results.

 

 

A Dac Extension Must Include The Publis Static Isactive Method

Hello everybody,

today  I want to share one line of code for Acuminator for error message:

PX1016 A DAC extension must include the public static IsActive method with the bool return type. Extensions which are constantly active reduce performance. Suppress the error if you need the DAC extension to be constantly active.

In case if you don't want to suppress Acuminator with a comment, you can do something like this inside of your extension:

public static bool IsActive() => true;

Certainly it is not the most elegant way of doing that, as better way could be usage of some attribute for this purpose, or for example use inheritance, but as of now, the smallest amount of code, you can use that line of code which is presented here. 

 

 

How To Get Key Fields Of Dac Class In Acumatica

 

Hello everybody,

recently for me it was needed to find out all key fields of DAC class. Code below does this:

 

public List<string> GetKeyFieldsOfDAC(Type dacClass)
{
    var result = new List<string>();
    var properties = dacClass.GetProperties().ToList(); 
    
    foreach (PropertyInfo info in properties)
    {
        var attrs = info.GetCustomAttributes(true);
        foreach (object attr in attrs)
        {
            if (attr.HasProperty("IsKey"))
            {
                dynamic typedAttribute = attr;
                if (typedAttribute.IsKey)
                {
                    result.Add(info.Name);
                }
            }
        }
    }
 
    return result;
}

 

And HasProperty method implementation goes below:

 

public static bool HasProperty(this object objectToCheck, string property)
{
    try
    {
        var type = objectToCheck.GetType();
        var prop = type.GetProperty(property);
        if (prop != null)
        {
            return true;
        }
    }
    catch (AmbiguousMatchException// it means we have more then one property
    {
        return true;
    }
 
    return false;
}

 That is not the most elegant solution in my life, and if you want to suggest a better one, please feel free to suggest.

 

How To Avoid Copy Paste With Help Of Attributes In Acumatica

 

Hello everybody,

today I want to leave a short note on how to avoid Copy/paste with help of custom attributes. 

Imagine following scenario. You have some set of duplicated code, which you need to apply at FieldSelecting . One of the ways of achieving this can be creation of some class and method within this class, which will handle that functionality, and then just copy/paste creation of the instance of the class at any place, where you need to have that business logic applied.

But you can use another way. You can use custom attributes. You can create your attribute, and then use that attribute over all places, where you may have a need for calling your business logic. In order to work that properly you'll need to inherit your Attribute from PXEventSubscriberAttribute, IPXFieldSelectingSubscriber . For example you can accomplish it like this:

 

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Parameter | AttributeTargets.Method)]
public class SomeAttribute : PXEventSubscriberAttributeIPXFieldSelectingSubscriber
{
    protected Type _TargetField;
    protected Type _DacType;
    
 
    public SomeAttribute(Type dacType, Type targetField)
    {
        _DacType = dacType;
        _TargetField = targetField;
    }
 
    public virtual void FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
    {
var graph = sender.Graph;
//and some other logic
}

Also this can be applied to the field like this:

 public class YourDacClass

{

    [Some(typeof(DacClass), typeof(DacClass.someField))]
    [PXUIField(DisplayName = "Value")]
    public virtual string SomeField { getset; }

}

 

and that's it. Now you can have move your duplication logic to attribute SomeAttribute, and enjoy smaller amount of code.