Submition Types In Acumatica

 

Hello everybody,

today I want to leave a really short notice on how you can submit data into Acumatica. There are three ways:

  • Contract-based REST API
  • Contract-based SOAT API
  • Screen-based SOAP API

Historically the first was screen based SOAP API, and with time two others were added. Later on I hope to add description of others as well.

 

Where Log Of Visual Studio Is Located

 

Hello everybody,

today I want to leave a short note on where to search for log file of Visual Studio. 

It lives here:

C:\Users\{USER}\AppData\Roaming\Microsoft\VisualStudio .....\{visual studio version}\ActivityLog.xml

Whenever I speak about log files with any kind of developer, I see round eyes and trembling voice with a question, why on earth should I look into log file?

The reason is simple, sometime you may get error message like this: "Error HRESULT E_FAIL has been returned from a call to a COM component" during adding reference to your class library. 

What may stand behind that error message? No ideas? The same was with me, but after looking into log file, we have found there following statement:

Microsoft.visualstudio.shell.interop.IVsReferenceManager2 within the Microsoft.VisualStudio.Shell.Interop.11.0.dll

and some additional close to abra cadabra statements, but googling that error message was much easier. 

Finally we applied following steps:

#1 Open "Developer Command Prompt for VS 2017" as Admin

#2 CD into "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\PublicAssemblies"

#3 Run "gacutil -i Microsoft.VisualStudio.Shell.Interop.11.0.dll"

Summary

Remember in which location lives log of Visual Studio. With it's help you'll be able to make miracles related to bugs. Another idea to keep in mind, take Microsoft as a pattern, and have your own log, especially of errors in your apps. 

 

How To Refresh Cache Of Acumatica

 

Hello everybody,

today I want to leave a comment on how to refresh cache of Acumaitca.

As usually I start with this method:

 

ViewName.View.RequestRefresh();

 

But I found that it not always work. For my surprise RequestRefresh not works for some reasons. I think reason for this may be that Acumatica has two caches: caching of data and caching of queries.  

If that is the case, I use another approach ( more hardcore ) 

 

ViewName.View.Cache.Clear(); // clearing cached data

ViewName.View.Cache.ClearQueryCache(); // clearing cached queries.

 

Second approach works a bit better, because it clears not only data, but also clears cached queries, and as outcome clearing results

 

How To Display Images In Grid Of Acumatica

 

Hello everybody,

today I want to leave a short post on how to display images in grid of Acumatica. 

I'll demonstrate it on sample of Sales Orders pages, which is known as SO301000.

End result will look like this:

 

In order to make it work, I've done the following:

  1. Created extension to SOOrderEntry and added there some kind of reading of url images
  2. Created DAC class for demo purposes
  3. Added few controls and css/js on customized so301000 page.

Now a bit more details. For SOOrderEntry I've created following extension:

    public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
    {
	    public PXSelect<SOImageItem> Images;
 
	    protected virtual IEnumerable images()
	    {
		    var result = new List<SOImageItem>();
			result.Add(new SOImageItem()
			{
				ID = 1,
				ImageUrl = "https://img.grouponcdn.com/deal/074cef17e1fc40c69e309870fcfbc8d7/d7/v1/c700x420.jpg",
				ID2 = 2,
				ImageUrl2 = "https://cdn1.shoebacca.com/catalog/product/P/K/PK54467_1l.jpg?quality=80&bg-color=255,255,255&fit=bounds&height=&width="
			});
 
		    
		    result.Add(new SOImageItem()
		    {
			    ID = 3,
			    ImageUrl = "https://cdn1.shoebacca.com/catalog/product/P/K/PK54467_2l.jpg?quality=80&bg-color=255,255,255&fit=bounds&height=&width=",
			    ID2 = 4,
			    ImageUrl2 = "https://cdn1.shoebacca.com/catalog/product/P/K/PK54467_4l.jpg?quality=80&bg-color=255,255,255&fit=bounds&height=&width="
			});
 
		    result.Add(new SOImageItem()
		    {
			    ID = 5,
			    ImageUrl = "https://cdn1.shoebacca.com/catalog/product/P/K/PK54467_6l.jpg?quality=80&bg-color=255,255,255&fit=bounds&height=&width=",
			    ID2 = 6,
			    ImageUrl2 = "https://cdn1.shoebacca.com/catalog/product/P/K/PK54477_1l.jpg?quality=80&bg-color=255,255,255&fit=bounds&height=&width="
			});
		    
		    result.Add(new SOImageItem()
		    {
			    ID = 7,
			    ImageUrl = "https://cdn1.shoebacca.com/catalog/product/P/K/PK54477_2l.jpg?quality=80&bg-color=255,255,255&fit=bounds&height=&width=",
				ID2 = null,
				ImageUrl2 = null
			});
 
			return result;
	    }
    }

and following DAC class:

[Serializable]
public class SOImageItem : IBqlTable
{
	public abstract class iD : IBqlField
	{
	}
 
	[PXInt(IsKey = true)]
	public virtual int? ID { getset; }
 
	public abstract class imageUrl : IBqlField
	{
	}
 
	[PXString(IsKey = true)]
	public virtual string ImageUrl { getset; }
 
	public abstract class iD2 : IBqlField
	{
	}
 
	[PXInt(IsKey = true)]
	public virtual int? ID2 { getset; }
 
	public abstract class imageUrl2 : IBqlField
	{
	}
 
	[PXString(IsKey = true)]
	public virtual string ImageUrl2 { getset; }
 
}

Then on page so301000, following staff was added:

<style>
    img {
        height100px;
        width100px;
        resizeboth;
    }
</style>

And final piece tab:

	<px:PXTabItem Visible="True" Text="Images"  BindingContext="form">
		<Template>
			<px:PXGrid runat="server" ID="grdImages" Width="100%" DataSourceID="ds">
				<Levels>
					<px:PXGridLevel DataMember="Images">
						<RowTemplate>
						    <px:PXNumberEdit runat="server" ID="CstPXNumberEdit5" DataField="ID"  Width="100"/>
							<px:PXTextEdit runat="server" ID="CstPXTextEdit4" DataField="ImageUrl"  />
                            
						    <px:PXNumberEdit runat="server" ID="PXNumberEdit2" DataField="ID2"  Width="100"/>
						    <px:PXTextEdit runat="server" ID="PXTextEdit1" DataField="ImageUrl2"  />
							
						</RowTemplate>
                        <Columns>
                            <px:PXGridColumn DataField="ID" Width="100" />
                            <px:PXGridColumn DataField="ImageUrl" Type="Icon" Width="350"   />
                            
                            <px:PXGridColumn DataField="ID2" Width="100" />
                            <px:PXGridColumn DataField="ImageUrl2" Type="Icon" Width="350"   />
                        </Columns>
					</px:PXGridLevel>
                </Levels>
			</px:PXGrid></Template></px:PXTabItem></Items>
        <CallbackCommands>
            <Search CommitChanges="True" PostData="Page" ></Search>
            <Refresh CommitChanges="True" PostData="Page" ></Refresh>
            <Refresh CommitChanges="True" PostData="Page" ></Refresh>
            <Search CommitChanges="True" PostData="Page" ></Search>
        </CallbackCommands>
        <AutoSize Enabled="True" Container="Window" ></AutoSize>
    </px:PXTab>

After that I was able to see result, that is shown on the screenshot of begining of the article.

 

 

How To Deal With Read Commited Snapshot Error Message In Acumatica

 

Hello everybody,

today I want to leave SQL fix for error message:

"There are problems on database server side:

READ_COMMITTED_SNAPSHOT is not set for current database.

On your Acumatica instance it may look liike this:

For fixing run this SQL:

ALTER DATABASE Saddleback_staging SET READ_COMMITTED_SNAPSHOT ON

 

How To Use Autofac In Acumatica With Global Graph And Single Registration

 

Hello everybody,

today I want to leave a short notice on how to use Autofac in Acumatica, but with single registration. In this article I've descirbed how to use Autofac for resolving interface < -- > class implementation. 

But one of my collegues Deebhan Hari pointed that with my usage registration of classes will happen on each roundtrip and for each graph leading to potential memory leack.

Definetely not something, we would like to have. After small conversation, we managed to add to Autofac singleton, which allowed us to have situation when only once per lifetime of the process Autofac 

registers class only once.

 

 

using System;

using PX.Data;

using Autofac;

 

namespace SingleRegistrationDemo

{

       public class AllGraphsExtension : PXGraphExtension<PXGraph>

       {

         public override void Initialize()

         {

             // Implemented Singleton, so that our KNCustomCaseCommonEmailProcessor is registered only once when needed.

             var single = SingletonCustomCaseCommon.Instance;

         }

       }

 

    public sealed class SingletonCustomCaseCommon

    {

        private static readonly Lazy<SingletonCustomCaseCommon>

            lazy =

            new Lazy<SingletonCustomCaseCommon>

                (() => new SingletonCustomCaseCommon());

 

        public static SingletonCustomCaseCommon Instance { get { return lazy.Value; } }

 

        private SingletonKNCustomCaseCommon()

        {

            PX.Objects.EP.EmailProcessorManager.Register(new ClosedCasesReOpenV2.CustomCaseCommonEmailProcessor());

        }

    }

}

 

 

How To React On Clicking On Abort Button In Acumatica Processing Screen

 

Hello everybody,

today I want to leave a notice with proposal on how to program reaction on clicking of Abort button in processing screen.

Recently it become needed for me to program some functionality to happen after user clicks on button Abort of processing screen. 

In my case I needed somehow to program exit from some threads which were running in parallel and I needed to finish one iteration of threads and then exit from each of those threds.

One more point was that just terminating of threads was also a bad idea. After a while I have found IPXCustomInfo interface. With that interface you can gain control on what to do in case of user 

clicking on Abort button. In my case I did the following:

  1. Created my own implementation of IPXCustomInfo like this:
public class PXImportCallback : IPXCustomInfo
{
    public void Complete(PXLongRunStatus status, PXGraph graph)
    {
        switch (status)
        {
            case PXLongRunStatus.Aborted:
                PXDatabase.Update<Sync>(
                    new PXDataFieldAssign<Sync.lastModifiedDateTime>(DateTime.Now),
                    new PXDataFieldAssign<Sync.wasExecuted>(false));
                break;
 
            case PXLongRunStatus.Completed:
                break;
 
            case PXLongRunStatus.InProcess:
                break;
 
            case PXLongRunStatus.NotExists:
                break;
        }
    }
}

As you can see, very simple interface, which requires of you to implement only one method: Complete, and inside of that method program supposed reaction.

Then for each StartOperation I've added following lines:

PXLongOperation.StartOperation(thisdelegate
{
    PXLongOperation.SetCustomInfo(new PXImportCallback());
 
    var orderFromDb = PXSelectReadonly<

and that's all! Each time users clicks on Abort, my programmed reaction appears, and I can clean memory and delete no longer needed files.

 

 

Create View If Not Exists In Acumatica Customization

 

Hello everybody,

today I want to leave a short post on how to create some custom view in Acumatica Customization if that view doesn't exist:

if not exists (select * from sysobjects where name='CustomerSelector' and xtype='V')
begin
exec (
    'CREATE view [CustomerSelector] as 
		select Distinct b.CompanyID, cc.Phone1, a.City, a.CountryID, b.TaxRegistrationID, c.CuryID, cc.Salutation, c.CustomerClassID, b.Status
		from BAccount b inner join customer c on b.BAccountID = c.BAccountID inner join [Address] a 
		on a.BAccountID = b.BAccountID inner join Contact cc on cc.BAccountID = b.BAccountID'
		)
 
end

This code will create view CustomerSelector only if such view doesn't exist in Acumatica

 

How To Override Properly Createpaymentproc Method Of Soorderentry Graph In Acumatica

 

Hello everybody,

today I want to leave short note on how to override and call CreatePaymentProc method of Acumatica which I discovered today with Naveen from Kensium.

My favorite way of overriding methods in Acuamtica with usage of Action and passing there parameters doesn't work. That is because Acumatica uses in method CreatePaymentProc out modifier. Due to this, delegate declaration is needed. 

After some efforts and refactorings we found following code that is working:

public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
    public delegate void CreatePaymentBase(SOOrder order, out PXGraph target, string paymentType);
 
    [PXOverride]
    public virtual void CreatePaymentProc(SOOrder order, out PXGraph target, string paymentType,
        CreatePaymentBase baseAction)
    {
        baseAction(order, out target, paymentType);
 
        var resultGraph = target as ARPaymentEntry;
        resultGraph.Document.Current.ExtRefNbr = "12xx14";
    }
}

With such code you can call base method, and modify what it produces.

How To Shrink Database Of Acumatica With Rebuilding Of

 

Hello everybody,

today I want to leave another portion of SQL Server optimization for Acumatica database. In case if your db become huge, and you want to make it smaller, you can try following SQL code:

DECLARE @Table NVARCHAR(128)  
DECLARE @Database NVARCHAR(128)
DECLARE @Command NVARCHAR(500)
 
PRINT N'Shrinking database files'
DBCC SHRINKDATABASE(0)
 
PRINT N'Rebuilding all indexes'
SET @Database = DB_NAME()
SET @Command = 'DECLARE TableCursor CURSOR FOR SELECT ''['' + TABLE_CATALOG + ''].['' + TABLE_SCHEMA + ''].['' + 
    TABLE_NAME + '']'' as TableName FROM [' + @Database + '].INFORMATION_SCHEMA.TABLES 
    WHERE TABLE_TYPE = ''BASE TABLE'''   
EXEC (@Command)  
OPEN TableCursor   
 
FETCH NEXT FROM TableCursor INTO @Table   
WHILE @@FETCH_STATUS = 0   
BEGIN   
    PRINT 'Rebuilding all indexes on ' + @Table    
    SET @Command = 'ALTER INDEX ALL ON ' + @Table + ' REBUILD'
    EXEC (@Command) 
FETCH NEXT FROM TableCursor INTO @Table   
END   

this code does two steps:

  1. Shrink database
  2. Rebuild indexes

Remember for yourself forever that any shrink will destroy your indexes. So each time you decide, or risk to make shrink your database don't forget to rebuild indexes. Otherwise you'll be hugely surprised to discover that also db is small, but performance is terrribly bad.

Just want to say that I've tried that approach on db of one of mine customers and results were the following: 646 Gb got shrinked to 161 Gb. Pretty impressive, huh?

And of course, word of warning. Never try that SQL, without recent back up of your production.