AX 2012 – Business Operation Framework - Create Batch without using RunBaseBatch Framework - Part I

 

Introduction:

You can develop components / write business logic and later can be hosted as services on AOS with help of Windows communication foundation. These services later can be used by or integrated with the third party applications in order to communicate with Dynamics AX.

BOF Artifacts:

Data Contract Class:

By name only you can identify that this class is going to hold input parameters and query. In simple terms these are fields/controls which we add on ‘Dialog’ to get input from user like FromDate, query criteria’s through select button.

To identify class as Data Contract, we need to use [DataContractAttribute] as below,

And for parm methods, [DataMemberAttribute]

Note:Thumb rule, if you have 10 fields on ‘Dialog’ then you should have 10 parm method.

Service Operation Class:

This class contains main business logic for which you designed/create ‘Data Contract’ class.

UI Builder Class:

BOF automatically generates ‘Dialog UI’ based upon Data Contract class, but if we wanted to access dialog fields at run time for validations like ‘enabled/allowEdit/Lookup’ then we need to create separate class for user interface.

Let us follow below steps in order to create batch class without using ‘RunBaseBatch’ framework, instead we make use of new BOF framework.

Step1:

Create Data Contract class as below,

  1. [DataContractAttribute]
  2. class Tutorial_TestDataContract
  3. {
  4. TransDate transDate;
  5. CustAccount custAccount;
  6. }

For each variable, create parm method and add [DataMemberAttribute] as below,

  1. [DataMemberAttribute]
  2. public TransDate parmTransDate(TransDate _transDate = transDate)
  3. {
  4. transDate = _transDate;
  5. return transDate;
  6. }

//

  1. [DataMemberAttribute]
  2. public CustAccount parmCustAccount(CustAccount _custAccount = custAccount)
  3. {
  4. custAccount = _custAccount;
  5. return custAccount;
  6. }

Step 2:

Once you done with data contract class,  create class to write business logic which will make use of above input parameters. It’s like ‘run’ method of any batch class where we write actual business logic.

  1. class Tutorial_TestBatchServiceOperation extends SysOperationServiceController
  2. {
  3. }

Create ‘new’ method as below

  1. public void new(identifierName _className = "", identifierName _methodName = "", SysOperationExecutionMode _executionMode = 0)
  2. {
  3. super();
  4. this.parmClassName(_className);
  5. this.parmMethodName(_methodName);
  6. this.parmExecutionMode(_executionMode);
  7. }

Create ‘Construct’ method as below

  1. public static Tutorial_TestBatchServiceOperation construct()
  2. {
  3. ClassName className;
  4. MethodName runMethodName;
  5. SysOperationExecutionMode execMode = SysOperationExecutionMode::Synchronous;
  6. Tutorial_TestBatchServiceOperation testBatchServiceOp;
  7. className = classStr(Tutorial_TestBatchServiceOperation);
  8. runMethodName = methodStr(Tutorial_TestBatchServiceOperation, runMyLogic);
  9. testBatchServiceOp = new Tutorial_TestBatchServiceOperation(className,
  10. runmethodName,
  11. execMode);
  12. testBatchServiceOp.parmDialogCaption("Tutorial SysOperation Batch");
  13. return testBatchServiceOp;
  14. }

//Method which will act as entry point to your business logic

//You can compare this method to 'run' method of any class

  1. public void runMyLogic(Tutorial_TestDataContract _data)
  2. {
  3. ;
  4. info(strFmt("You entered %1, %2", _data.parmCustAccount(), _data.parmTransDate()));
  5. }

Finally main method to make class to run

  1. public static void main(Args args)
  2. {
  3. Tutorial_TestBatchServiceOperation testBatch;
  4. testBatch = Tutorial_TestBatchServiceOperation::construct();
  5. testBatch.startOperation();
  6. }

Step3:

It’s very important to run ‘Incremental CIL Generation’ since above class will get executed on AOS.

Step4:

Run above class ‘Tutorial_TestBatchServiceOperation ‘ and you can see similar/familiar user interface for batch class

image

Click ‘Ok’ and you will get output as below

image

In next part will try to address how to access fields on dialog at run-time to control validations like ‘allowEdit/enabled’ etc….

Untill then ‘Happy Batching :) ‘

AX 2012 - X++ Code to 'Create and Post Purchase Order Invoice'

Find below job to create and post purchase order in Dynamics AX 2012

Note: Referring contoso demo data, 'CEU' company

static void CreatePOAndInvoice(Args _args)
{
    PurchTable      purchTable;
    PurchLine       purchLine;
    VendTable       vendTable = VendTable::find("3008");
    AxPurchTable    axPurchTable;
    AxPurchLine     axPurchLine;
    PurchFormLetter purchFormLetter;
   
    //Create Purchase order
    purchTable.initFromVendTable(vendTable);
   
    axPurchTable = axPurchTable::newPurchTable(purchTable);
    axPurchTable.parmPurchaseType(PurchaseType::Purch);
    axPurchTable.parmDocumentStatus(DocumentStatus::PurchaseOrder);
    axPurchTable.parmAccountingDate(systemDateGet());
    axPurchTable.parmDeliveryDate(01\06\2012);
    axPurchTable.parmPurchStatus(PurchStatus::Backorder);
    axPurchTable.doSave();

    //Create PurchLine for item 1000
    purchLine.initFromPurchTable(purchTable);

    axPurchLine = AxPurchLine::newPurchLine(purchLine);
    axpurchLine.parmItemId("1000");
    axPurchLine.parmPurchQty(10);
    axPurchLine.parmPurchPrice(100);
    axPurchLine.doSave();

    //Posting PO Confirmation,I guess its mandatory
    //You cannot do invoice without doing PO confirm
    purchTable = axPurchTable.purchTable();
    purchFormLetter = PurchFormLetter::construct(DocumentStatus::PurchaseOrder);
    purchFormLetter.update(purchTable, strFmt("Inv_%1", purchTable.PurchId));

    //Posting PO Invoice
    purchFormLetter = PurchFormLetter::construct(DocumentStatus::Invoice);
    purchFormLetter.update(purchTable, strFmt("Inv_%1", purchTable.PurchId));

}

'Always fun to explore and learn new stuffs'

AX 2012 - How to debug Code in Visual Studio

This post basically addresses how to debug code in Visual studio.
Most of code running on AOS runs in CIL environment, so it cannot be debugg in Microsoft Dynamics AX Debugger.
You might have confused/surprised why ax debugger is not opening inspite of  inserting breakpoint at particular place. It means code might be running in CIL and to debug visual studio 2010 is required.

Step1:
Make sure AOS Service runs on account which you logged in. Right click on AOS Service and change log on property to logged in windows credentials.
Log off windows and then re log in.          

Step2:
Open visual studio and click on AX Application explorer (Shortcut Ctrl + D)
AOT opens and you can browse nodes as you used to do in Dynamics AX.
Open the object which you want to debug and insert breakpoint.

Step3:
Then in Visual studio, Click on Debug->Attach process

As shown in above image, First make sure two check boxes at bottom are marked.
Then only you can find and able to select AX32Serv.exe(AOS)  process and click on attach button.

Note : When you are doing this step 3 for first time it prompts you to Restart Visual studio, kindly select the same option.

Step4:
You done with setting up visual studio to debug code running in CIL.
Now restrart process in Dynamics AX which you want to debugg and you can find Visual studio debugger opened for you.
Continue debugging with hotkeys as you use to do in AX debugger like F10/F11.


Happy Debugging :)



AX 2012 - Editor tips and tricks for fast development/coding

Hi Friends,

Long back i seen video on new improvements made to existing X++ Editor. Lot of features have been introduced to get look and feel of visual studio editor.
Among all, I am very much impressed with 'Inserting Code Snippets' feature.
           - During coding in editor, if you want to create main method
           - You will make use of template and select main method or construct
           - But in 2012, just type main and click tab will insert main method prototype.

So thought of making video for same, watch it


Really you will enjoy this new feature and finish development much faster compare to 2009.

"Need is mother of all innovations"

   

Dynamics AX 2012 - X++ code to create General Journal


static void Demo_CreateGLJournal(Args _args)
{
    AxLedgerJournalTable journalTable;
    AxLedgerJournalTrans journalTrans;
    container            accEntryPattern;
    container            offSetEntryPattern;
    ;

    journalTable = new AxLedgerJournalTable();
    journalTrans = new AxLedgerJournalTrans();

    //Journal Name
    journalTable.parmJournalName("GenJrn");
    journalTable.save();

    journalTrans.parmJournalNum(journalTable.ledgerJournalTable().JournalNum);
    journalTrans.parmTransDate(systemDateGet());
    journalTrans.parmAccountType(LedgerJournalACType::Ledger);

    //LedgerDimension  => Ledgeraccount, DAX 2009
    accEntryPattern = ["601501", "601501", 0];
    journalTrans.parmLedgerDimension(AxdDimensionUtil::getLedgerAccountId(accEntryPattern));

    journalTrans.parmAmountCurDebit(2000);

    //OffsetLedgerDimension => OffsetLedgerAccount,  DAX 2009
    offSetEntryPattern = ["401100", "401100", 0];
    journalTrans.parmOffsetAccountType(LedgerJournalACType:: Ledger );
    journalTrans.parmOffsetLedgerDimension(AxdDimensionUtil::getLedgerAccountId( offSetEntryPattern));
 
    journalTrans.save();

    info(strFmt("Journal %1 created", journalTable.ledgerJournalTable().JournalNum));
}

How to post with Financial dimensions:

Format : 
["DisplayValue", "MainAccount", NumberOfDimensions, "DimensionName", "DimensionValue"];

E.g:
accEntryPattern = ["601501-Test", "601501", 1, "Department", "OU_1"]

Enjoy exploring 2012 :)

Enable/Disable Fact boxes, Preview Panes in AX2012 UX

In Microsoft Dynamics AX 2012, if you want to disable factboxes/preview panes across application then you can do so.
It's not recommended to do this activity but this will help in troubleshooting performance issues assoicated with opening forms in ax2012 by controlling 'Timeout' parameter as below.

Go to ->System Administration->Setup->Client performance options

Visit  Ax2012-client-performance-options for detailed explaination by Ax performance team.

Thanks axperf team :)


Dynamics AX 2012 - Workflow Development in 2 hrs


Hi Friends,

First of all would like to wish you all Very "Happy and Dynamics new year -2012".

You all might be aware/heard of new changes related to worklow architecture and development.
So this post basically addresses,

1. Workflow Architecture changes
2. Workflow Development  wizards
3. Generic class for submit/resubmit events on all workflows in AX.


1. Workflow Architecture changes

In 2012, AOS service has gone tremendous changes like

- Now you can directly host WCF services on AOS.
- Earlier version we were using IIS to interact with WWF(Windows workflow foundation) and      
           WCF (Windows communication foundation).
- Because of above change, now no need to install workflow component separately
- Just run the workflow configuration wizard (available in System administration->Setup)
- Workflow templates/configuration were made available across companies/per company level.
- Workflow template is renamed to Workflow types

2. Workflow Development through wizards.

Let us develop workflow for
        'Customer approval- New created customer should be approved through workflow'

Step 1:
          Create a query for custTable say 'CustApprWorkflowQry' in AOT->Queries

Step 2:
          Duplicate enum 'PurchReqWorkflowState' and rename it to 'CustApprWorkflowState' and drag it to CustTable Table.

Step 3:
          Override 'canSubmitToWorkflow' method on Table->CustTable and paste below code.

//BP Deviation Documented
                public boolean canSubmitToWorkflow(str _workflowType = '')
                {
                    boolean ret;

                    ret = this.RecId != 0 && this.CustApprWorkflowState ==
                    CustApprWorkflowState::NotSubmitted;

                    return ret;
                 }


Create new method on CustTable as below to update worklow state during its life cycle.

                //BP Deviation documented
                public static void UpdateCustWorkflowState(RefRecId _recId, CustApprWorkflowState _state)
                {
                    CustTable custTable = CustTable::findRecId(_recId, true);

       ttsBegin;

       custTable.CustApprWorkflowState = _state;
       custTable.update();

       ttsCommit;
}


Step 4:
            Create workflow type (template/configuration) through wizard available in 2012.

Run wizard as below:

AOT->Workflow-> Workflow types  (Right click ->Add-Ins-> workflow type wizard...

Specify values as shown in below image


Click on next, as shown in below image wizard will create workflow eventhandlers class and menu items for you.

Paste below code to update workflow state.

//BP Deviation Documented
public void started(WorkflowEventArgs _workflowEventArgs)
{
    CustTable::UpdateCustWorkflowState(_workflowEventArgs.parmWorkflowContext().parmRecId(), CustApprWorkflowState::Submitted);
}

//BP Deviation Documented
public void completed(WorkflowEventArgs _workflowEventArgs)
{
   CustTable::UpdateCustWorkflowState(_workflowEventArgs.parmWorkflowContext().parmRecId(), CustApprWorkflowState::Completed);
}

//BP Deviation Documented
public void canceled(WorkflowEventArgs _workflowEventArgs)
{
CustTable::UpdateCustWorkflowState(_workflowEventArgs.parmWorkflowContext().parmRecId(),   CustApprWorkflowState::PendingCancellation);
}


Step 5:
           Create workflow approval through wizard available in 2012.

Run wizard as below:

AOT->Workflow-> Approvals  (Right click ->Add-Ins-> Approval wizard...

Specify values as shown in below image

Click on next, as shown in below image wizard will create workflow element eventhandlers and menu items for you.

Paste below code to update workflow state.

//BP Deviation Documented
public void started(WorkflowElementEventArgs _workflowElementEventArgs)
{
   CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),   CustApprWorkflowState::Submitted);
}

//BP Deviation Documented
public void returned(WorkflowElementEventArgs _workflowElementEventArgs)
{
   CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),  CustApprWorkflowState::Returned);
}

//BP Deviation Documented
public void changeRequested(WorkflowElementEventArgs _workflowElementEventArgs)
{
        CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),  CustApprWorkflowState::ChangeRequest);
}

//BP Deviation Documented
public void completed(WorkflowElementEventArgs _workflowElementEventArgs)
{
    CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), CustApprWorkflowState::Approved);
}

//BP Deviation Documented
public void canceled(WorkflowElementEventArgs _workflowElementEventArgs)
{
       CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),  CustApprWorkflowState::PendingCancellation);
}

Step 6:
          Enable workflow on CustTableListPage form and alos drag field CustApprWorkflowstate on form overview grid, as below

          CustTableListPage->Design, set properties as below

Step 7:
          Download below class to activate workflow on submit and resubmit.

          This is generic class and with little modification can be used for all different worklow's in AX.
          Download Class XPO :
         
         Once you download and import class,  change below menu-items associated with submit and resubmit actions.



Step 8:
          Run Incremental CIL generation, AOT->Right click-> Incremental CIL generation

You are done with development and can configure workflow in AR->Setup
After activating above workflow configuration test it by creating new customer in CustTableListPage form.

Hope you enjoyed this new style of  workflow development which will take 1-2 hours for any new basic  workflow approval :)