Wednesday, November 8, 2017

D365Ops : Table browser extension available on Chrome Browser

A new extension has been introduced to access Table browser without opening visual studio.For the  Business users or Application consultants working with AX, don't have the privilege of going into the AOT from the Client even with 'System Administrator' role in AX

If you are using Google chrome, then you have a shortcut. You can add the Chrome extension - Table Browser Caller for D365 for Operations -https://chrome.google.com/webstore/detail/ax-table-browser-caller/nahbldacmaibopfiiaoboloegpobpccn


Once you have it installed, there will be a small icon on the top-right corner of your screen, clicking upon which you will get options:
  1. Table Browser caller - where you can set the Search, Legal entity, Language.
  2. Config - In this tab, you can set the Base URL for your installation

Few advantages:
  • You can browser the entire built-in table list with links to open Table browser directly.
  • You can view / edit records using Table browser without opening Visual studio.
  • The access permissions can be controlled by setting up roles from within AX



Tuesday, April 11, 2017

BPCheckMissingDeleteActions or Delete actions missing in table ProjInvoiceTable.Extension which is related to table HcmWorker with relation name HCMWorker

In Table relation property- give any delete action
ex: Restricted
tablerelation

Tuesday, September 27, 2016

Extension framework - Solution to Ax 7 Rainer

In 2012( both AX 2012 and the year 2012) something called Extension framework was introduced. It’s little known and sparsely used. 
There were some performance limitations so even the few who knew it, did not prefer using it. In D365 as part of the drive to move away from over layering, this pattern/framework is being extensively used. 
I came across it in the spring release code base. I would like to first introduce you to it and then explain the changes. If you are already familiar with it. You can skip the first part. 
 
Now, let’s get back to the topic. This is more of a semi-framework / semi-code pattern. It was introduced to remove the necessity of overriding base types in order to extend the child types. Let me be more detailed. 
Of all the examples I came across this was the simplest… So to save time I copied it below. The original post is available here. 
 
In AX 2012 
I have a base enum defining the different Dynamics products: 

 Next, I have a base class named Dynamics. 
 It has a new method that's made private (forcing people to use the static constructor) and a run method that has an exciting infolog message. 
private void new() { }  public void Run() {      info("base class"); } 
 Next, we'll make a derived class for each of the Dynamics products: 
 Each one will extend the base class and override the Run method to show a different infolog. Below is the code for the DynamicsAX and DynamicsCRM class, you get the idea for the other classes... 
public class DynamicsAX extends Dynamics { }  public void Run() {      super();      info("Dynamics AX"); } 
 
public class DynamicsCRM extends Dynamics { }  public void Run() {      super();      info("Dynamics CRM"); } 
 Great. So now that we have our sub types, we can create the "classic" construct method on our base class. On the base class "Dynamics", create a new static construct method, which takes our base enum as a parameter, and returns the correct sub type for it. 
public static Dynamics construct(DynamicsProduct _product) {      Dynamics dynamics = null;      switch (_product)      {          case DynamicsProduct::AX:              dynamics = new DynamicsAX();              break;          case DynamicsProduct::CRM:              dynamics = new DynamicsCRM();              break;          case DynamicsProduct::GP:              dynamics = new DynamicsGP();              break;          case DynamicsProduct::NAV:              dynamics = new DynamicsNAV();              break;          case DynamicsProduct::SL:              dynamics = new DynamicsSL();              break;          default:              throw error("Unsupported product");      }      return dynamics; } 
 Nothing too crazy here, a very traditional pattern you see a lot in Dynamics AX. Finally, we can create a static main method on the base class to run it. For the sake of this article, we'll just hard code the product to be AX (because that's what we're really here for, isn't?). Feel free to create menu items with parmEnum or something, but to keep it short and to the point, hard coding will do. So again, on base class "Dynamics", add the main method: 
public static void main(Args _args) {      Dynamics dynamics = Dynamics::construct(DynamicsProduct::AX);      dynamics.Run(); } 
 And of course, when we run this, we'll see the infologs showing. The base class declaring it's the base, and the sub type declaring it's Dynamics AX. Perfect!  At this point, let's take a break and step back. What's wrong with this pattern? First of all, there is no way to extend this code base without either changing the code or overlayering (the construct method). Secondly, from a more design approach, it seems bad that the base class has to have explicit knowledge of all the sub classes. Put together, this is not very extension-friendly. If we would have two ISV products that both extend this, someone will have to merge the code. And nobody likes merging code.  So, extension framework! The idea is to use the new attributes feature in the X++ language to decorate the classes, and make a constructor that can dynamically find the right sub class, assuming there is one. So first, we need to create a new attribute. An attribute is basically a class that extends the base SysAttribute class. An attribute can have different properties, some mandatory, some optional. In this case, we want to use the attribute on a class to tie it back to one of the enum values. So, our attribute should have a property to hold that enum value. The base enum was called "DynamicsProduct" so we'll declare a member variable to hold that. We'll call our attribute class "DynamicsProductAttribute". 
class DynamicsProductAttribute extends SysAttribute {      DynamicsProduct product; } 
 Since we don't really have class properties in X++, we need to create a set/get method, or as X++ likes to call it, a PARM method. Basically, a way to access the member variable to read or update it. 
public DynamicsProduct parmDynamicsProduct(DynamicsProduct _product = product) {      product = _product;      return product; } 
 Now, to make this a mandatory property on the attribute we can add it as a method parameter on the new method. So, override the new method on the "DynamicsProductAttribute" class. 
public void new(DynamicsProduct _dynamicsProduct) {      super();      this.parmDynamicsProduct(_dynamicsProduct); } 
 So, that's really it for the attribute class. Now we can actually start using it to decorate our sub classes. No need to touch the base class, but on all the sub classes, we want to add the attribute in the classdeclaration. Again, I'll just show the example for the DynamicsAX and Dynamics CRM classes: 
[DynamicsProductAttribute(DynamicsProduct::AX)] public class DynamicsAX extends Dynamics { } 
 
[DynamicsProductAttribute(DynamicsProduct::CRM)] public class DynamicsCRM extends Dynamics { } 
 Decorate each sub-class with the attribute and the correct enum value. This approach makes a whole lot more sense. Now each sub-class is declaratively tying back to a specific enum value. So finally, we of course need to change the constructor on the base class to make use of this at run time. This is really the only part where there's a "framework" really in place. On the base class "Dynamics", we're going to change the static construct method. Now, we can ask the extension framework to grab us the class with a specific attribute. Of course we're interested in the DynamicsProductAttribute, but more importantly we're interested in the class that has that attribute but also has a specific value for its property (in our case, the enum DynamicsProduct). The extension framework just asks us what base class we want to grab sub classes for, as well as an INSTANCE of the attribute it should have. The reason we need an instance is because it needs all the properties (in our case we only have 1, but you could have several properties). To get all this done, we can call the static "getClassFromSysAttribute" method on the "SysExtensionAppClassFactory" class. We give it the base class name ("Dynamics") and the attribute we want, which has to be an instance, so create an instance and set the correct property value. Your new and improved (and shortened) construct method should look like this now: 
public static Dynamics construct(DynamicsProduct _product) {      Dynamics dynamics = SysExtensionAppClassFactory::getClassFromSysAttribute(classStr(Dynamics), new DynamicsProductAttribute(_product));      return dynamics; } 
 Since our static main was already using construct, you can just re-run the main and everything should work. Note that this class factory business caches EVERYTHING. If you've run it once, and then re-run after making changes, it may not pick up new classes or changed attributes. From the Tools menu, you can run Tools / Caches / Refresh Elements to flush the cache so it will pick up your changes. 
 
In D365 
 
Keeping the concepts same, this has been modified slightly to make it more easier for consumption. The old way still works but you couldn’t send arguments to initialize. 
We basically needed only one thing here, an attribute to identify the correct child class. This needed extending SysAttribute, now in addition to that  
  1. we will have to implement SysExtensionIAttribute. 
  2. Implement methods parmCacheKey and useSingleton 
  3. Use SysExtensionGenericInstantiation to instantiate the members of class  
  4. Use getClassFromSysAttributeWithInstantiationStrategy  instead of getClassFromSysAttribute 
 
Now let’s look at an example : 
 
The attribute class now looks like this –  
class PurchRFQTypeFactoryAttribute extends SysAttribute implements SysExtensionIAttribute 
{ 
    PurchRFQType purchRFQType; 
 
    public void new(PurchRFQType _purchRFQType) 
    { 
        purchRFQType = _purchRFQType; 
    } 
 
    /// Returns the key used for storing cached data for this attribute. 
    public str parmCacheKey() 
    { 
        return classStr(PurchRFQTypeFactoryAttribute)+';'+int2str(enum2int(purchRFQType)); 
    } 
 
    /// Determines if the same instance should be returned by the extension framework for a given extension. 
    /// When returning false, the SysExtension framework will create a new class instance for every invocation. 
    /// If the class is immutable, consider returning true to save memory and gain performance. 
    public boolean useSingleton() 
    { 
        return false; 
    } 
 
} 
 
Here enumeration of type PurchRFQType will determine what the child class will be. So, the child classes will be decorated like this: 
 
[PurchRFQTypeFactoryAttribute(PurchRFQType::PurchReq)] 
class   PurchRFQCaseLineType_PurchReq extends PurchRFQCaseLineType 
 
[PurchRFQTypeFactoryAttribute(PurchRFQType::Purch)] 
class   PurchRFQCaseLineType_Purch extends PurchRFQCaseLineType 
 
The construct in the base class is already refactored. And it looks like this: 
 
    static PurchRFQCaseLineType construct(PurchRFQCaseLine _purchRFQCaseLinePurchRFQCaseTable _purchRFQCaseTable = _purchRFQCaseLine.purchRFQCaseTable()) 
    { 
        PurchRFQTypeFactoryAttribute        attribute       = new PurchRFQTypeFactoryAttribute(_purchRFQCaseLine.rfqType); 
        SysExtensionGenericInstantiation    instantiation   = new SysExtensionGenericInstantiation(_purchRFQCaseLine, _purchRFQCaseTable); 
        PurchRFQCaseLineType                instance        = SysExtensionAppClassFactory::getClassFromSysAttributeWithInstantiationStrategy(classStr(PurchRFQCaseLineType), attribute, instantiation) as PurchRFQCaseLineType; 
 
        return instance; 
    } 
 
The instantiation should match the signature of new() in the base class. Here it has 2 arguments. 
    protected void  new(PurchRFQCaseLine _purchRFQCaseLinePurchRFQCaseTable _purchRFQCaseTable) 
 
If interested please look at the code in SysExtensionGenericInstantiationIt supports only 5 arguments. So, if you have more than 5 mandatory arguments in base class new method. You are doomed. Just kidding. Microsoft will take care of it. They have the onus to change all the base classes J 
Also you can look at getClassFromSysAttributeWithInstantiationStrategy to understand the search logic to find the correct class. (I don’t want to explain these make this email longer than its already is and we all need some homework, don’t we?) 
 
Now, when I want to introduce a new type of RFQ case line, all I had to do was add a new element to enum extension and then declare a class like this: 
[PurchRFQTypeFactoryAttribute(PurchRFQType::Subcontract)] 
class ACMPbmPurchRFQCaseLineType_Subcontract extends PurchRFQCaseLineType