How to override BuildTAxRequest method of APInvoiceEntryExternalTax class

Hello everybody,

today I want to leave a short techy post on how to override method BuildTaxRequest of APInvoiceEntryExternalTax class.

public class APInvoiceEntryExternalTaxExtPXGraphExtension<APInvoiceEntryExternalTaxAPInvoiceEntry>
{
    [PXOverride]
    protected virtual GetTaxRequest BuildTaxRequest(APInvoice invoiceFunc<APInvoiceGetTaxRequestbaseAction)
    {
        var result = baseAction(invoice);
        //Your code
 
        return result;
    }
}

Reason for such a behavior is a fact that class APInvoiceEntryExternalTax is graph extension for graph. That's why such a construction is needed.

How to overrde Authorize CC Payment Action in Acumatica

Hello everybody,

as it was mentioned in one of my previous blog posts, regarding overriding base actions of Acumatica graphs, family of graph extensions grows and grows. 

 

Today I want to share one more code snippet which you can use for extending modification of Acumatica actions. Below goes code fragment, which you can use for modification of Authorize CC Payment:

public class PaymentTransactionExt : PXGraphExtension<PaymentTransactionSOOrderEntry>
{
    [PXOverride]
    public virtual IEnumerable AuthorizeCCPayment(PXAdapter adapterFunc<PXAdapterIEnumerablebaseFunc)
    {
        
        var result = baseFunc(adapter);
        
        return result;
    }
}

Of what I foresee now, is a loooooot of work for Acumatica developers upgrading to a newer versions of Acumatica. 

Why I say so? 

Because as usually ISV have their code in SOOrderEntry extensions. But now they either will need to move their code from SOOrderEntry extensions or for example to reference Base1 ( which is your extension ) as well as Base.

Reason why Acumatica does this is probably following few general programming principles of: SRP ( single responsibility principle ), DRY ( Dont Repeat Yourself ) principle, Open Closed principle on graph level, which in long term will bring more stability to the system.

Basic advice will be this, don't expect that upgrade of your code base to 2019 R2 will be as fast, as it used to be in the past, and before giving estimate which you used to give, pay special attention to how new actions are declared.

 

How to override ShopRates action in Sales Orders form

Hello everybody,

today I want to leave a short post on how to override Shop rates Action in Acumatica. 

I mean this button:

Below goes C# code, with which you can achieve it:

public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry.CarrierRatesSOOrderEntry>
{
    [PXOverride()]
    public virtual IEnumerable ShopRates(PXAdapter adapterFunc<PXAdapterIEnumerablebaseMethod)
    {
        //your code here
        var retVal = baseMethod?.Invoke(adapter);
        //and possibly here
        return retVal;
    }
}

As you can see from the code, life in Acumatica becomes more complex, and if in the past you've used to override directly your actions, now you'll need to create extension for extension in order to override some Actions. 

Similar issues I've seen in other places of SOOrderEntry, for example in AuthorizeCCPayment, CaptureCCPayment, etc.

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 add validation to Create shipment and confirm shipment in Acumatica

Hello everybody,

today I want to write a few words on my latest time spending in Acumatica. Recently I was asked to add additional validations to actions Create shipment:

and Confirm Shipment:

Idea was the following, if user clicks on Create shipment action or at Confirm Shipment action, some function should be executed which throws exception and prevents Creation/confirmation of shipment if some conditions are not meet. 

At first glance task was trivial. I supposed that all that will be needed, just override method Create Shipment of SOOrderEntry and Cofirm Shipment of SOShipmentEntry. And jumped right to the code. 

In order to modify behavior of those two methods, I've created override of Action of SOOrderEntry and added validation inside of that method. My code looked like this:

		[PXOverride]
		public IEnumerable Action(PXAdapter adapter, int? actionID, DateTime? shipDate, String siteCD, String operation, 
			String ActionName, 
			Func<PXAdapterint?, DateTime?, stringstringstringIEnumerable> baseMethod)
		{
            
			List<SOOrder> list = new List<SOOrder>();
			foreach (SOOrder order in adapter.Get<SOOrder>())
			{
				list.Add(order);
			}
			if (actionID == 1)
			{
                //throwed exception here!. WRONG WAY!!!!

I've tested it on Sales Orders page, got exception, added additional code and send it to QA with feeling that I'm great. Unfortunately I was far from making task as done. The next day QA told me that on processing screen my code didn't work at all, 

and asked me to deal with it in another way. As usually programmers and QA's have love-hate relationship, but I myself always happy to deal with QA. I can say that it's always better if QA return you a bug, then angry customer with your boss 

asks you to fix a bug.

So I started coding one more time. I've tried few other ways, for example I've overrided method Persist of SOShipmentEntry like this:

                [PXOverride]
		public void Persist(Action del)
		{
                      //if validation fails, throw exception here. WRONG WAY
}

and before giving that staff to QA I've decided to give a test for this approach and much to my shame it also didn't work as expected. And on the level of processing screen I've got plenty of weird exeptions, and not even exceptions created by my code.

In case if nothing works, the only think that you can do involves deep immersion in Acumatica source code. After deeging deeper here is what I've found inside of action Create shipment:

  1. Create shipment method is not executed right away after click on Actions -> Create shipment. Before that some plumbing code is executed.
  2. Save.Press() is executed multiple times, so when I've throwed exception, then methods for Shipment creation as well as confirmation weren't executed at all.
  3. After pretty big amoung of plumbing code method CreateShipment is executed.

After seeing such behavior I've decided to override methods CreateShipment and ConfirmShipment. Both of those methods are implemented in graph SOShipmentEntry. Override in Acumatica looks pretty stratightforward, especially with anonymous delegates.

Both of those methods I've included in extension of SOShipmentEntry, and methods looks like those:

[PXOverride]
public void CreateShipment(SOOrder order, int? SiteID, DateTime? ShipDate, bool? useOptimalShipDate,
    string operation, DocumentList<SOShipment> list, PXQuickProcess.ActionFlow quickProcessFlow,
    Action<SOOrderint?, DateTime?, bool?, stringDocumentList<SOShipment>, PXQuickProcess.ActionFlow> baseCreateShipment)
{
    var unpaidBalacne = GetDocumentBalance(order);
 
    ShipmentValidator.ValidateShipment(Base, order, unpaidBalacne, WorkFlowMessages.creditLimitExceeded);
    baseCreateShipment(order, SiteID, ShipDate, useOptimalShipDate, operation, list, quickProcessFlow);
}
[PXOverride]
public virtual void ConfirmShipment(SOOrderEntry docgraph, SOShipment shiporder,
    Action<SOOrderEntrySOShipment> baseConfirmShipment)
{
    var shipLines = PXSelect<SOShipLineWhere<SOShipLine.shipmentNbrEqual<Required<SOShipLine.shipmentNbr>>,
            And<SOShipLine.shipmentTypeEqual<Required<SOShipLine.shipmentType>>>>>
        .Select(Base, shiporder.ShipmentNbr, shiporder.ShipmentType).ToList().Select(a => a.GetItem<SOShipLine>());
 
    foreach (SOShipLine shipLine in shipLines)
    {
        ValidateSOShipLine(shipLine, false);
    }
    baseConfirmShipment(docgraph, shiporder);
}

After those changes each page, including processing pages started to work smoothly.

Summary

All of those conclusions that I've made would be impossible to make without debugging of Acumatica source code. Next time when I'll face some not working out of the box my code, I'll jump into debugging and proper debugging right away.

 

 

How override Persist method in Acumatica

Hello everybody,

today I want to show sample of code on overriding Persist method in Acumatica. 

Consider following scenario, you need to modify saving logic of screen Purchase Orders in Acumatica. How you can achieve this? Following steps can help you to do this:

  1. Create extension class for POOrderEntry
  2. Override Perist method

Both of those details implemented below:

public class POOrderEntryExt : PXGraphExtension<POOrderEntry>
{
 
    [PXOverride]
    public void Persist(Action del)
    {
        //Here you can add some of your code that should be executed before persisting PO Order to database
        del();
    }
 
}

With such simple steps you can modify persisting logic to any needed behaviour. Or even turn it off.

How to override action "Create " at form SO301000 or "Sales orders"

Hello everybody,

today I want to document one important piece of functionality in Acumatica. Sales order screen. This is very important screen and has many staff. One of the important screens in it is "Sales orders"  screen. From prospective of understanding Acumatica source code of method "Actions" has plenty of food for mind.

Take a look at it's declaration:

                public PXAction<SOOrder> action;
[PXUIField(DisplayName = "Actions", MapEnableRights = PXCacheRights.Select)] [PXButton] protected virtual IEnumerable Action(PXAdapter adapter, [PXInt] [PXIntList(new int[] { 1, 2, 3, 4, 5 }, new string[] { "Create Shipment""Apply Assignment Rules",                 "Create Invoice""Post Invoice to IN""Create Purchase Order" })] int? actionID, [PXDate] DateTime? shipDate, [PXSelector(typeof(INSite.siteCD))] string siteCD, [SOOperation.List] string operation, [PXString()] string ActionName ) {

}

 

From this declaration alone you can see that in order to have a button with menu items you need to 

  1. Declare member of type PXAction with lower case name ( in case of "Sales order" screen member is named action )
  2. Create method with Uppser case name ( in case of "Sales order" screen method is named Action )
  3. Besides passing PXAdatapter into method pass also in method integer which is attributted with PXInt, PXIntList
  4. Other attributes and their purpose you can figure out by yourself 

Here I want to leave piece of code that allows you to append this method with your own piece of functionality:

public delegate IEnumerable ActionDelegate(PXAdapter adapter, Nullable<Int32> actionID, Nullable<DateTime> shipDate,
   String siteCD, String operation, String ActionDelegateName);
 
[PXOverride]
public IEnumerable Action(PXAdapter adapter, Nullable<Int32> actionID, Nullable<DateTime> shipDate, String siteCD,
    String operation, String ActionName, ActionDelegate baseMethod)
{
    var currentSoOrder = Base.CurrentDocument.Current;
//and other code }

 

If to summarize, you'll need:

  1. Declare delegate
  2. Declare action

 

Override Equals method of value types

Hello everybody.

Today I want to give some demo.

using System;
using System.Diagnostics;

namespace StackOverflowQuest
{
    class Program
    {
        struct StructTest
        {
            public string TestString { get; set; }

            //public override bool Equals(object obj)
            //{
            //    var ct = (StructTest)obj;
            //    return ct.TestString == this.TestString;
            //}
        }
        class ClassTest
        {
            public string TestString { get; set; }

            public override bool Equals(object obj)
            {
                var ct = obj as ClassTest;
                if (ct == null)
                    return false;
                return ct.TestString == this.TestString;
            }
        }

        static void Main(string[] args)
        {
            StructTest st = new StructTest() { TestString = "water"};
            StructTest st2 = new StructTest() { TestString = "water" };

            ClassTest ct1 = new ClassTest() { TestString = "water" };
            ClassTest ct2 = new ClassTest() { TestString = "water" };

            int numberOfIterations = 500000;

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();
            for (int i = 0; i < numberOfIterations; i++)
            {
                ct1.Equals(ct2);
            }
            sw2.Stop();
            Console.WriteLine("class perfomance = {0} Elapsed Milliseconds", sw2.ElapsedMilliseconds);

            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            for(int i = 0; i < numberOfIterations; i++)
            {
                st.Equals(st2);
            }
            sw1.Stop();
            Console.WriteLine("structs perfomance = {0}  Elapsed Milliseconds", sw1.ElapsedMilliseconds);
            Console.ReadKey();
        }
    }
}

Take note of commented method of Equals method. If I execute that code on my machine, I'm getting difference in perfomance in 6 times. But if to uncomment Equals, then class and struct have comparable perfomance.

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:

[Update, thanks to Taras Vynar]

public class YourExtension : PXGraphExtension<SomeBasicGraph>
{
  [PXOverride]
  public void MethodForOverriding(string viewName, IDictionary keys, IDictionary values, Action<string, IDictionary, IDictionary> methodDel)
  {
    //some your code
    methodDel(viewName, keys, values);
    //again some of your code. 
    return res;
  }
}

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