Thursday, November 29, 2012

Get Financial Dimension Value from Worker Position

To get financial dimension value from worker position, add a new method in hcmWorker Table with script like below:

public static str getDimensionValue
          (HcmWorkerRecId _workerRecId, 
           Name _DimensionName, 
           utcdatetime _asOfDate = DateTimeUtil::utcNow())
{
    DimensionAttributeValueSetStorage             dimStorage;
    str                                                             dimValue;
    Counter                                                     Counter;
    HcmPositionDefaultDimension                    _HcmPositionDefaultDimension;
    RecId                                                       _DefaultDimension;
    ;
    select _HcmPositionDefaultDimension where
    _HcmPositionDefaultDimension.Position == HcmWorker::getPrimaryPosition(_workerRecId);
    dimStorage = DimensionAttributeValueSetStorage::find

                         (_HcmPositionDefaultDimension.DefaultDimension);
    for (Counter=1 ; Counter<= dimStorage.elements() ; Counter++)
    {
         if(DimensionAttribute::find(dimStorage.getAttributeByIndex(Counter)).Name == _DimensionName)
         {
               dimValue = dimStorage.getDisplayValueByIndex(Counter);
         }
    }
    return dimValue;
}


After it, if we wanna make display method to show financial dimension, we can use method above. In example we wanna display dimension site from a worker who have PersonnelNumber = "00001". The script is like below :

display str Site()
{
          return hcmWorker::getDimensionValue(
                    hcmWorker::findByPersonnelNumber("00001").recid, "Site");
}

Sunday, October 14, 2012

Automatic timeout shutdown value is stored in UserInfo table

static void User_Timeout(Args _args)
{
UserInfo userInfo;
;
ttsbegin;
while select forupdate *
from userInfo
{
userInfo.autoLogOff = 30;
userInfo.update();
}
ttscommit;
}

Saturday, October 13, 2012

How export data to csv file in Ax 2009

public static void main(Args _args)
{
    Commaio file;
    container line;
    InventTable inventTable;
    #define.filename("C:\\dpk_Items.csv")
    #File
    ;
    file = new Commaio(#filename , #io_write); or  file = new Commaio(#filename , 'W');
    //file.outFieldDelimiter(';');
    if( !file || file.status() != IO_Status::Ok)
    {
        throw error("File Cannot be opened");
    }
    while select inventTable
    {
        line = [inventTable.ItemId,inventTable.ItemName];
        file.writeExp(line);
    }
}
  As per this you can save the document in any format such as doc,txt,xls only.

Wednesday, August 29, 2012

How to find default dimension like cost centre purpose or department

static void setDefaultDimensionToCustomer(Args _args)
{
  CustTable custTable; 
  Struct struct = new Struct(); 
  container ledgerDimension; 
  DimensionDefault DimensionDefault;
  ;
    
   
  struct.add('Abteilung', '02');    
  struct.add('Kostenstellen', '00200');
  ledgerDimension += struct.fields(); 
  ledgerDimension += struct.fieldName(1); 
  ledgerDimension += struct.valueIndex(1);
  ledgerDimension += struct.fieldName(2); 
  ledgerDimension += struct.valueIndex(2);
  
 
  ttsBegin;
  DimensionDefault = AxdDimensionUtil::getDimensionAttributeValueSetId(ledgerDimension); 
  custTable = CustTable::find("22027", true); 
  custTable.DefaultDimension = DimensionDefault;
  custTable.update();
  ttsCommit; 

Wednesday, August 22, 2012

Reading dll from database


Private void Button2_click(object sender,EventArgs e)
{
   Byte[] result = null;
String dsn = “”;
SqlConnection con = new SqlConnection(dsn);
Con.open();
Sqlcommand cmd= new SqlCommand(“select * from StoredDLL”,con);
cmd.CommandType = CommandType.Text;
SqlDataReader reader = cmd.ExecuteReader();
If(reader.HasRows)
{
  While(reader.Read())
{
    resullt = (Byte[])reader[0];
}
File.WriteAllBytes(@”D:\som\Test1.dll”,result);
Object results = ReadandAccessDLL();
Messagebox.show(result.tostring());
}
Else
{
Messagebox.show(“No Rows found”);
}
Reader.close();
Con.close();
}
Private object ReadandAccessDLL()
{
Assembly a=Assembly.LoadFile(@”D:\som\Test1.dll”);
Object result = null;
For each (Type type in a.GetTypes())
{
  If(type.IsClass== true)
{
   If( type.FullName.EndsWith(“.” + “class1”))
{
   Object obj = Activator.CreateInstance(type);
  Object[] args =  {56,86};
Result = type.InvokeMember(“sum”,
BindingFlags.Default|BindingFlags.InvokeMethod,null,obj,agrs);
}
}
}
Return result;
}

Wednesday, August 1, 2012

Create your own shortcuts in AX forms

In AX it is virtually impossible to control the shortcuts of buttons. Even though button properties like KeyTip indicate that you should be able to have some control, nothing really works.
Here is a tip on how you can catch special keyboard combinations yourself, and thus create your own shortcuts.

First you need to call a method from USER32.DLL to figure out if a certain key is pressed. You could for example implement this on the WinAPI class:

static boolean getKeyPressed(int _keyCode)
{
    DLL winApiDLL = new DLL('USER32');
    DLLFunction getKeyState = new DLLFunction(winApiDLL, 'GetAsyncKeyState');
    int result;
    ;

    getKeyState.returns(ExtTypes::WORD);
    getKeyState.arg(ExtTypes::DWORD);

    result = getKeyState.call(_keyCode);

    if ((result & 0x8000) == 0x8000)
        return true;
    else
        return false;
}
The method is called with what’s called a virtual key code, which is the code of the key you want to know is pressed or not. You can find a list of these keyboard codes on MSDN:http://msdn.microsoft.com/en-us/library/dd375731(VS.85).aspx

On your form you need to implement a method that is executed again and again while the form is idle. The method needs to check if your special key combination is pressed, do the action associated with the key and set the method up for next iteration.
It could look like this:

void myKeyboardCheck()
{
    #define.ALT(0x12)
    #define.O(0x4F)
    #define.timeOut(10)
    ;

    // Check if this form is the foreground window of Windows
    if (winApi::getForegroundWindow() == this.hWnd())
    {
        // Check if ALT + O is pressed
        if (WinApi::getKeyPressed(#ALT) && WinApi::getKeyPressed(#O))
        {
            // Check if the button is enable
d            if (MyVerySpecialButton.enabled())
            {
                MyVerySpecialButton.clicked();
            }
        }
    }
    // Reset timer
    this.setTimeOut('myKeyboardCheck', #timeOut, true);
}

In the run method of the form, I set the above method up for the first iteration, and I change the label of the button to reflect the desired shortcut:

MyVerySpecialButton.text(MyVerySpecialButton.labelText() +' (o)');
this.myKeyboardCheck();

If you need to implemt this in more forms, you might want to build a small supporting framework in order to avoid repeating much of the same code over and over. The class DocuFileWatchDog could be a good pattern to look at.

If you need to catch keyboard combinations at a global level, you should hook into the Info.OnEventGoingIdle() method. Global reserved keys are defined under \Application Documentation\Global\Shortcutkeys.

I want to give a big thank you to Microsoft support for pointing me in the right direction. I can only wonder why Microsoft haven't gotten this stuff correctly wired up in the first place.

Monday, July 30, 2012

Creating and Posting Inventory ProfitLoss journals in DAX using .NET Business Connector


using System;
using Microsoft.Dynamics.BusinessConnectorNet;

namespace ProfitLossPostingAppl
{
    class AxProfitLossPostingEngine
    {
        static void Main(string[] args)
        {
            Axapta ax = new Axapta();
            // company name, language, object server, configuration
            // this uses Windows Authentication
            ax.Logon("cmul", null, "localhost", null);
            
            try
            {
                // Start a transaction
                ax.TTSBegin();

                // AxaptaRecord is a class that allows to work with Tables in AX
                AxaptaRecord header = ax.CreateAxaptaRecord("InventJournalTable");
                AxaptaRecord journalName = ax.CreateAxaptaRecord("InventJournalName");
                AxaptaRecord line = ax.CreateAxaptaRecord("InventJournalTrans");
                AxaptaRecord inventTable = ax.CreateAxaptaRecord("InventTable");
                AxaptaRecord warehouse = ax.CreateAxaptaRecord("InventDim");

                // You can call static table methods using the following syntax
                journalName = ax.CallStaticRecordMethod("InventJournalName", "find", "IPL") as AxaptaRecord;

                // There is a set of predefined methods on the AxaptaRecord class, like the clear(), initValue, DML operations, etc.
                header.Clear();
                header.InitValue();
                // You can call table object methods as well, not only static
                header.Call("initFromInventJournalName", journalName);
                header.Insert();

                line.Clear();
                line.InitValue();
                line.Call("initFromInventJournalTable", header);
                // You cannot use table fields directly as in X++. Instead you have set/get methods
                line.set_Field("itemId", "B-R14");

                // Instead of using static table methods (like find) you can execute a direct SQL statement and receive the result in the AxaptaRecord object
                inventTable.ExecuteStmt("select * from %1 where %1.ItemId == 'B-R14'");
                // If you receive more that one record you can iterate through them using Next (as in AX)
                line.Call("initFromInventTable", inventTable);

                line.set_Field("Qty", 160.0);

                warehouse.Clear();
                warehouse.set_Field("InventLocationId", "MW");

                warehouse = ax.CallStaticRecordMethod("InventDim", "findOrCreate", warehouse) as AxaptaRecord;
                
                line.set_Field("InventDimId", warehouse.get_Field("inventDimId"));
                line.Insert();

                // Notice AxaptaRecord is passed by reference here
                ax.CallStaticRecordMethod("InventJournalTable", "initTotal", header);
                header.Update();

                ax.TTSCommit();
                
                // You can call static class methods the same way you call table static methods, but using a different method on Axapta class
                // So in case you wrote the posting in X++, you would be able to call it, passing the JournalId as the argument
                // int numOfLinesPosted = (int)ax.CallStaticClassMethod("DEV_ProfitLossEngine", "postProfitLossJournal", header.get_Field("JournalId"));
                
                // Or, you can use the AxaptaObject class to accomplish the same from C# 
                // You can initialize a new class using the Axapta class method
                // AxaptaObject journalCheckPost = ax.CreateAxaptaObject("InventJournalCheckPost");
                
                // Or using a static method, if that suites your needs better
                // Notice here that an object of type AxaptaRecord is passed into a method that expects InventJournalTable as the argument
                AxaptaObject journalCheckPost = ax.CallStaticClassMethod("InventJournalCheckPost", "newPostJournal", header) as AxaptaObject;
                // You can object methods the same way you would on a table
                journalCheckPost.Call("parmShowInfoResult", false);
                journalCheckPost.Call("parmThrowCheckFailed", true);
                journalCheckPost.Call("parmTransferErrors", false);
    
                journalCheckPost.Call("run");
                int numOfLinesPosted = (int)journalCheckPost.Call("numOfPostedLines");

                Console.WriteLine(String.Format("{0} line(s) have been successfully posted", numOfLinesPosted));
                Console.WriteLine("JournalId is " + header.get_Field("JournalId"));
                Console.WriteLine("Press any key to continue ...");

                ax.Logoff();
            }
            catch (Exception ex)
            {
                ax.TTSAbort();
                ax.Logoff();

                Console.WriteLine(ex.Message);
            }

            Console.ReadKey();
        }
    }
}

Thursday, July 26, 2012

Table and field Finding


static void testing(Args _args)
{
    TreeNode            node;
    TreeNode            childNode;
    TreeNodeIterator    nodeIt;
    FilePath            path;
    str             Property;
    identifiername  Type,Mandatory;
    ;


    path        = @'\Data dictionary\Tables\PFSComponentTypes\Fields';
    node        = TreeNode::findNode(path);
    nodeIt      = node.AOTiterator();
    childNode   = nodeIt.next();


    while(childNode)
    {
        //info(childNode.treeNodeName());
        ///info(childNode.AOTname());
        Property    = childNode.AOTgetProperties();
        Type        = findproperty(Property, 'Type');
        Mandatory   = findproperty(Property, 'Mandatory');
        info(strFmt("-%1-%2-%3",childNode.AOTname(),Type,Mandatory));
        childNode = nodeIt.next();
    }
}

Friday, July 13, 2012

AX 2012 : Delete All Transactions

We need to modify the SysDatabaseTransDelete.handletable method with the below code :

void handleTable(SysDictTable sysDictTable)

{

    TableGroup      tableGroup;

    if (tableSet.in(sysDictTable.id()))

        return;

    tableSet.add(sysDictTable.id());

    if (sysDictTable && !sysDictTable.isTmp() && !sysDictTable.isMap())

    {

        tableGroup = sysDictTable.tableGroup();

        // Handle company specific tables to be deleted

        if (sysDictTable.dataPrCompany())

        {

            switch(tableGroup)

            {

                case TableGroup::Transaction:

                case TableGroup::WorksheetHeader:

                case TableGroup::WorksheetLine:

                //FIX - Support new AX2012 transaction table types

                case TableGroup::TransactionHeader:

                case TableGroup::TransactionLine:

                    this.handleTransTable(sysDictTable);

                    break;

                default:

                    this.handleNonTransTable(sysDictTable);

                    break;

            }

        }

        else

        {

            // Handle global tables to be deleted

            switch(tableGroup)

            {

                case TableGroup::Transaction:

                case TableGroup::WorksheetHeader:

                case TableGroup::WorksheetLine:

                //FIX - Support new AX2012 transaction table types

                case TableGroup::TransactionHeader:

                case TableGroup::TransactionLine:

                    this.handleGlobalTransTable(sysDictTable);

                    break;

                default:

                    break;

            }

        }

    }

}

Tuesday, June 26, 2012

Job to Import Vendor/Customer Postal Address in Dynamics Ax2012

static void PostalAddressCreate(Args _args)
  
   {
  
     VendTable vendTable;
  
     DirParty dirParty;
  
     DirPartyPostalAddressView PostalAddress;
  
     CommaTextIo file;
  
     container record;
  
     str countyId, zipcode;
  
     ;
  
     file = new CommaTextIo("C:\\VendorPostalAddress.csv",'r');
  
     file.inFieldDelimiter(',');
  
     while (file.status() == IO_Status::Ok)
  
     {
  
       record = file.read();
  
       vendTable = VendTable::find(conPeek(record,1));
  
       if (vendTable.RecId)
  
       {
  
         try{
  
         dirParty = DirParty::constructFromCommon(vendTable);
  
         PostalAddress.Street = conPeek(record,2);
  
         PostalAddress.BuildingCompliment = conPeek(record,3);
  
         PostalAddress.City = conPeek(record,4);
  
         PostalAddress.CountryCurrencyCode = conPeek(record,5);
  
         PostalAddress.CountryRegionId = conPeek(record,6);
  
         countyId = conPeek(record,7);
  
         if (Global::strStartsWith(countyId,'~'))
  
         {
  
           countyId = strDel(countyId,1,1);
  
         }
  
         PostalAddress.County = countyId;
  
         //PostalAddress.District = conPeek(record,8);
  
         //PostalAddress.DistrictName = conPeek(record,9);
  
         //PostalAddress.IsLocationOwner = conPeek(record,10);
  
         //PostalAddress.isocode = conPeek(record,11);
  
         PostalAddress.IsPrimary = conPeek(record,12);
  
         PostalAddress.LocationName = conPeek(record,16);
  
         PostalAddress.State = conPeek(record,24);
  
         zipcode = conPeek(record,30);
  
         if (Global::strStartsWith(zipcode,'~'))
  
         {
  
           zipcode = strDel(zipcode,1,1);
  
         }
  
         PostalAddress.ZipCode = zipcode;
  
         PostalAddress.ValidFrom = datetobeginUtcDateTime(1\1\2012, DateTimeUtil::getUserPreferredTimeZone()) ;
  
         PostalAddress.ValidTo = datetobeginUtcDateTime(1\1\2154, DateTimeUtil::getUserPreferredTimeZone()) ;
  
         PostalAddress.Party = vendTable.Party;
  
         if (!dirParty.createOrUpdatePostalAddress(PostalAddress).RecId)
  
           {
  
             info(VendTable.AccountNum);
  
           }
  
         }
  
         catch(Exception::Error)
  
         {
  
           info(VendTable.AccountNum);
  
         }
  
       }
  
     }
  
   }  

How to identify the user that was used to change an object from AOT in AX2012

Get the object name for which we need to track these (user and date&time) information's. Login to SQL Server Management Studio an...