Friday, 9 December 2016

SSRS – No connection could be made

In a Microsoft Dynamics AX 2012 test system, I recently saw the following error when attempting to print any SSRS report:
No connection could be made because the target machine actively refused it
Error when creating SSRS report: No connection could be made because the target machine actively refused it
I confirmed that the relevant instance of SSRS was running, and decided that the problem was related to the port referred to in the error: 8203. I knew that this test AOS was the only one configured on this server and the default ports were being used – including 8201 for the Service port. I could not track down why port 8203 was being used.
After some help from Microsoft Support in Munich, the cause was found to be the Microsoft Dynamics AX configuration file that SSRS was using. The file is called Microsoft.Dynamics.AX.ReportConfiguration.axc and can be found in one of these locations (depending on the version of SQL being used).
If you are using SQL Server 2008: \Program Files\Microsoft SQL Server\MSRS10.[SSRSInstanceName]\Reporting Services\ReportServer\bin.
If you are using SQL Server 2008 R2: \Program Files\Microsoft SQL Server\MSRS10_50.[SSRSInstanceName]\Reporting Services\ReportServer\bin.
If you are using SQL Server 2012: \Program Files\Microsoft SQL Server\MSRS11.[SSRSInstanceName]\Reporting Services\ReportServer\bin.
The SSRSInstanceName can be found in AX at System Administration -> Setup -> Business intelligence -> Reporting Services -> Report servers in the ‘Server instance name’:
SSRS Report servers
SSRS Report servers
When I edited the Microsoft.Dynamics.AX.ReportConfiguration.axc file, I was able to search for several references to 8203:
AX Config file
AX Config file contains references to port 8203. The ports for the AOS and WSDL are also wrong.
I also noted that the ports for the AOS and WSDL were wrong.
Presumably, I could have corrected the information in the file. But the file is actually a standard AX client configuration file, and I simply replaced it with a copy of the .axc file I had been using to point the AX client at the test AOS. It would also have been possible to create this file using the AX 2012 Configuration Tool. After doing this, I was able to create SSRS output – a restart of the AOS or SSRS was not required.

Tuesday, 8 November 2016

TimeConsumed() function in ax 2012

timeConsumed()–a very useful function in Global class in AX 2012 [x++]

There is a very useful function timeConsumed() in Global class which we can use to calculate the time taken to execute business logic in AX 2012.

This function will return time consumed string in the form of X hours X minutes X seconds. If X is 0 – will not include the value + text.
It handles up to a 24 hour time difference not dependent on start/end time. If time consumed > 24 hours will only report time over 24 hour intervals.

Below is the example:

static void timeConsumed(Args _args)
{
    FromTime startTime = timeNow();
    int i;
    str dummyStr;
    ;
 
    for (i = 1 ; i <= 500000; i++)
    {
        dummyStr += int2str(i);  
    }
     
    info(strFmt("Total time consumed is  %1", timeConsumed(startTime, timeNow())));
}


static void Milliseconds(Args _args)
{
    TimeInMS        startTime,endTime;
    int i;
    str dummyStr;
    ;
    startTime = WinAPI::getTickCount();

    for (i = 1 ; i <= 500000; i++)
    {
    dummyStr += int2str(i);
    }
    endTime = WinAPI::getTickCount();
    info(strfmt("%1 Milliseconds",endTime-startTime));
}

Monday, 19 September 2016

Restrict multiple times user login in AX 2012

Currently in Ax 2012 the user can login  multiple times in application, so to restrict users to open Ax 2012  multiple times we can use the following code.
---->Before implementing this please take backup of your application files
Open Classes --> info --> StartupPost metod
and copy following code into this method

void startupPost()
{// To restrict user login form second login
    xSession                    session;
    SysClientSessions           sysClientSessions;
    UserId                      currentUserId;
    int                         counter;  
    ;

    if(curUserId()!="Admin")
    {
        while select SysClientSessions
            where SysClientSessions.userId == curUserId()
                && SysClientSessions.Status == 1                  // 1 : Login 0 : Logout
                && SysClientSessions.sessionType == 0       //  sysClientSessions.clientType == 0
        {
            session = new xSession(SysClientSessions.SessionId, true);
            if (session && session.userId())
            {
                counter++;
            }
        }
        if(counter>=2)
        {
            Box::stop("Already Logged-in : The same user id can't log in twice.");
            infolog.shutDown(true);
        }
    }

}

http://daynamicsaxaptatutorials.blogspot.in/2011/04/restrict-multiple-user-login-in-axapta.html

https://dynamicsuser.net/ax/f/technical/68340/user-permissions-in-ax2009-to-be-able-to-send-an-e-mail

http://archive.bottomline.com/collateral/technical_documents/TN10%20Microsoft%20Dynamics%20AX%20Connector%20User%20Security%20Permissions.pdf


Monday, 4 July 2016

Table Inheritance In Microsoft Dynamics Ax 2012

When you consider the use of inheritance between two tables, one table is the proposed base table, and the other is the proposed derived table.

should consider the use of inheritance between two tables when all the following conditions are true:

   1) There is no thought that there might be a 1-to-many or many-to-many relationship between the two tables.

    An existing row in the proposed base table, and the corresponding row in the derived table, both refer to the same item in the real world.

    Each row in the proposed base table has exactly one corresponding row in the derived table.

    If one row is ever deleted from either table, the corresponding row must also be deleted.

    The base table probably has at least two tables that derive from it.

    The two derived tables have fields for different kinds of things.
    The two derived tables refer to different variations of the general items that are tracked together in the base table.

    No item that is represented in a base table would ever be represented in more than one of its derived tables.

    The derived table is not meant for performance tuning of the physical database, such as placing an image column in its own table.

Example:
Create a table and name it as Base table.
[Note: For a temporary table ,we cannot set the support inheritance property to YES.]

create a field with datatype int64 and name it as InstanceRelationType.

Now set the Table property Support Inheritance --> Yes

create a field with datatype int64 and name it as InstanceRelationType.
create a field  with datatype str and name it as person.
create one more field with datatype int and name it as MyID.
Now set the table properties:

InstanceRelation Type --> InstanceRelationType
Abstract --> Yes

Create a new table and name it as Derived table.

set the table properties
Support Inheritance --> Yes
extends to -->BaseTable

create one more table and name it as Derived.

set the table properties
Support Inheritance --> Yes
extends to -->BaseTable

create a field with datatype str and name it ContactNo.

Now we will get the fields automatically in the Derived table.
Links:







Thursday, 30 June 2016

Cache in Dynamics Ax 2012

Caching Mechanism in AX:

Caching in simple terms, is a temporary storage area where frequently accessed data can be stored for rapid access. Once the data is stored in the cache, it can be used in the future by accessing the cached copy rather than re-fetching or recomputing the original data.

In Ax, we have 2 caches.

1.Server Cache
2.Client Cache

Client Cache is used only when a select is executed on client-tier. If a record is not in client cache, it looks in server Cache, and if not, it costs a database fetch. Maximum records stored in client cache are 100 per table, per company, where as, in ServerCache, this limit is 2000.

To know whether a record is fetched from client cache, server cache or database, use wasCached() of the TableBuffer used in Select.

select * from salesTable where salesTable.salesId == '000006';
info(strfmt("%1",salesTable.wasCached()));

We have 2 types of caching mechanisms in Ax:

  Set Based Cache – Caches a set of records.(EntireTable)
  Single-record Cache – Caches records based on Select Statement used.(NotInTTS, Found, FoundAndEmpty)

None: No data is cached or retrieved from the cache for this table.
This property value should be used for tables that are heavily updated or where it's unacceptable to read outdated data.

The Found and FoundAndEmpty caches cross transaction boundaries. The NotInTTS cache is newly created inside a transaction. This example, modified for the purposes of this topic, demonstrates how records are retrieved from the cache when the table's CacheLookup property is set to NotInTTS, and the PrimaryIndex property is set to a unique index on the AccountNum field.

Ex:

static void NotInTTSCache(Args _args) // X++, in AOT > Jobs.
{
    CustTable custTable;
    ;
    // The query looks for a record in the cache.
    // If the record does not exist in the cache,
    // the query accesses the database.
    select custTable
        where custTable.AccountNum == '4000';

    // The transaction starts.
    ttsbegin;

    // The cache is not used. The query accesses the database
    // and a record is placed in the cache.
    select custTable
        where custTable.AccountNum == '4000';

    // The query uses the database because
    // the forupdate keyword is used.
    select forupdate custTable
        where custTable.AccountNum == '4000';

    // The query uses the cache and not the database.
    select custTable
        where custTable.AccountNum == '4000';

    // The query uses the cache because
    // the forupdate keyword was used previously.
    select forupdate custTable
        where custTable.AccountNum == '4000';

    // The transaction is committed.
    ttscommit;

    // The query will use the cache.
    select custTable
        where custTable.AccountNum == '4000';
}

If the table CacheLookup property was set to Found or FoundAndEmpty, the first select statement inside the transaction (after the TTSBegin statement) would retrieve the record from the cache.

In AX 2012, table caching is more advanced than in previous versions, including support for joins, unique indexes (as opposed to primary indexes only), cross company queries, etc. (under certain constraints as explained in the above links).

Links:
https://msdn.microsoft.com/EN-US/library/bb314693.aspx

https://community.dynamics.com/ax/b/axsupport/archive/2015/02/20/dynamics-ax-table-caching-basic-rules
http://tech.alirazazaidi.com/exploring-data-cache-in-dynamics-ax-2012/

Monday, 27 June 2016

The history of Dynamics AX / Axapta

The history of Dynamics AX / Axapta

Microsoft Dynamics AX is originally developed the Danish company Damgaard A/S as Axapta. In 2002 Damgaard A/S merged with Navision Software A/S, into NavisionDamgaard A/S, eventually ended up calling them Navision A/S

The development and modification of software is done by its own integrated development environment, MorphX, which contains several tools such as a debugger, profiler and query interface. The development environment remains the same client application, thereby allowing access to these tools from the client application. The language used in Axapta is X ++.

1998 - Axapta 1.0 is released in March.

Released in the US and Denmark
Financial, trade, inventory management, logistics and production, Microsoft SQL Server 6.5
1998 - Axapta 1.5 - Early release in Norway, Sweden, Germany, UK, Netherlands, Austria, Switzerland, Belgium Spain and the European Union.

Publishing Manager
Call COM
Service Pack technology
Microsoft SQL Server 7.0

1999 - Axapta 2.0 - July:

Project Accounting module
WMS
External OLAP
Option Pack concept
ActiveX support
COM-connector and an early release of Axapta Object Server

2000 - Axapta 2.1 - January: Market demands from Germany, Austria, Switzerland and Spain.

Web tools and CSS (The first WebApp)
Microsoft SQL Server 2000, database log.
Receives Microsoft Windows 2000 logo.

2000 - Axapta 2.5 – December: Complete Web applications development environment.

Auto upgrade tool
ESS (Project)
Banking
First step of Load’n’Go
OLAP within Axapta
XML support
FA to Denmark, Austria and UK. Domains and ASP support
DBCS Support.

2001 - Axapta 2.5 Market Pack – October: Released in France and Italy.

Marketing Automation (CRM)
Commerce Gateway
Product Builder (Web application as well), training
Event Management (Web application as well).

2002 - Microsoft Axapta 3.0 - October:

Microsoft Axapta Enterprise Portal, intercompany collaboration.
New security and configuration keys.
Expanded geographical reach (more countries).
Demand planning.
Enhanced partner productivity tools.

2006 - Dynamics AX 4.0  - March:

  The seventh major Axapta release brought with it an updated look and feel. As the first version that Microsoft was involved in from the beginning it attempted to integrate better with existing Microsoft technologies.

AOS became a true Windows service
.Net business connector was provided
CLR Interoperability was introduced
XML data exchanges were supported through a set of code classes (Application Integration Framework)
Full Unicode support was introduced
Service Management module.

2008 - Dynamics AX 2009  - June: 

Originally named AX 4.1, later renamed to AX 5.0 (and finally AX 2009), the eighth major release of Axapta brings with it yet more improvements to the UI. This new version adds role-based concepts to both the Enterprise Portal and windows clients, support for timezones (utc), a new Site inventory dimension, and Enterprise Portal development through Visual Studio projects.

2011 - Dynamics AX 2011  - Q1:

 Sometimes dubbed AX 6, it is said to include additional improvements to the user interface and application enhancements focused on specific industries like Retail, Media & Entertainment, and Public sector. Originally AX 2011 was due to be released toward the middle of 2010, but this has since been put back to Q1 2011.

Dynamics AX 2012 Feature Pack:

 Released soon after AX 2012, the feature pack added a Retail solution in addition to the previously released industry-specific solutions.

Dynamics AX 2012 R2:

 Announced at the Convergence 2012 conference, AX 2012 R2 is due to ship in late 2012 and is expected to include enhanced support for Microsoft SQL Server 2012 as well as support for additional languages and markets

Tuesday, 14 June 2016

updating InventTrans when a line in PurchLine or SalesLine is created

I had a weird customization in the recent days and I wanted to share it with you guys. It is in AX 2012.

Our functional team wanted to add a column in the purchLine(Table) form and it should reflect in the InventTrans(Table) form.

Note: To see the Invent Transactions form, Open PurchLine form > Inventory > View > Transactions.

Let me tell you in steps to get the things done.

Step 1: Add a column of a datatype of your interest into the PurchLine Table and InventTrans Table.

Step 2: Open InventMovement class and add a new column for the above field to update it to InventTrans Table when a PurchLine is created and it should return an empty value. Check ProjId method for your reference.

Step 3:  Perform a Forward compilation to make the child classes of the InventMovement class to know about the above method.

Step 4: Override the above method in InventMov_Purch class and return PurchLine.yourfield.

Step 5: Finally, In the classes \Classes\InventMovement\initInventTransFromBuffer do the assignment. Eg: InventTrans.yourField = this.createdmethod(); (look at projId implementation)

Step 6: Compile the class InventMovement and done.

Now, the newly created field of the PurchLine should reflect in InventTrans form.

Leave the comments if you get any queries while performing it.

http://dynamicsuser.net/ax/f/11/t/75821

Friday, 27 May 2016

Periodic journal through x++ code


 static void CON_PeriodicJournal_Multiplelines(Args _args)
{
    LedgerJournalTrans          ledgerJournalTrans,LedgerJournaltrans1;
    LedgerJournalTable          ledgerJournalTable;
    ledgerJournalname           ledgerJournalname;
    NumberSeq                   numberSeq;
    NumberSequenceTable         numSeqTable;
    container                   cont1,cont2,ledgerDimension,offSetAcctPattern;
    DimensionDynamicAccount     ledgerDim, offsetledgerDim;
    ledgerJournalCheckPost      ledgerJournalCheckPost;
    int                         cnt;
    DimensionDefault            DimensionDefault;
    LedgerJournalPeriodicCopy   LedgerJournalPeriodicCopy;
    CopyMove                    CopyMove;
    LedgerJournalId             periodicLedgerJournalId,genjourLedgerJournalId;
    LedgerJournalACType         periodicACType,periodicOffSetACType;
    DimensionDynamicAccount     periodicAccount,periodicoffsetAccount ;
    AmountCurCredit             credit;
    RecId                       RecId;

     // find ledgerjournalname record
    select firstonly   ledgerjournalname where LedgerJournalName.JournalName =='PerJrn';

    //create ledger journal table
    ledgerjournaltable.journalname      = ledgerjournalname.journalname ;
    ledgerjournaltable.initfromledgerjournalname();
    ledgerjournaltable.name             = " May Periodic Journal";
    ledgerJournalTable.insert();

    /////Line 1 Created
    //ledgerJournalTable = LedgerJournalTable::find("00553");
      try
        {
            ttsbegin;
            ledgerJournalTrans.clear();
            ledgerJournalTrans.initValue();
            ledgerJournalTrans.JournalNum   = ledgerJournalTable.JournalNum;
            ledgerJournalTrans.TransDate    = today();
            ledgerJournalName = ledgerJournalName::find(ledgerJournalTable.JournalName);
            periodicLedgerJournalId = ledgerJournalTrans.JournalNum ;
            select firstOnly numSeqTable
                where numSeqTable.RecId  == ledgerJournalName.NumberSequenceTable;
            if (numSeqTable)
            {
                numberseq = numberseq::newGetVoucherFromCode(numSeqTable.NumberSequence);
                ledgerJournalTrans.voucher = numberseq.voucher();
            }

            //ledgerJournalTrans.Voucher              = voucher;
            ledgerJournalTrans.AccountType          = LedgerJournalACType::Vend;
            ledgerJournalTrans.OffsetAccountType = LedgerJournalACType::Ledger;
            // Main account dimensions

            periodicACType = ledgerJournalTrans.AccountType;
            periodicOffSetACType = ledgerJournalTrans.OffsetAccountType;


            cont1=conNull();
            cont2=conNull();
            ledgerDimension =conNull();
            cont2 += ['BusinessUnit','082','Department','023'];
            cnt =2;
            if(ledgerJournalTrans.AccountType  == LedgerJournalACType::Ledger)
            {
                cont1+=['MainAccount','112100',2];
                cont1+=cont2;
                ledgerDim=AxdDimensionUtil::getLedgerAccountId(cont1);

                if(ledgerDim==0)
                {
                        offSetAcctPattern = ['112100','112100'];
                        ledgerDim = AxdDimensionUtil::getLedgerAccountId(offSetAcctPattern);
                }

                ledgerJournalTrans.LedgerDimension  = ledgerDim;
            }
            else
            {
                ledgerDim = DimensionStorage::getDynamicAccount( '000021',ledgerJournalTrans.AccountType);
                ledgerJournalTrans.LedgerDimension  = ledgerDim;
                ledgerDimension +=cnt;
                ledgerDimension +=cont2;
                DimensionDefault = AxdDimensionUtil::getDimensionAttributeValueSetId(ledgerDimension);
                ledgerJournalTrans.DefaultDimension = DimensionDefault;
            }

            periodicAccount = ledgerDim;
            cont1=conNull();
            cont2=conNull();
            ledgerDimension =conNull();
            cont2 += ['BusinessUnit','082','Department','023'];
            cnt =2;
            if(ledgerJournalTrans.OffsetAccountType  == LedgerJournalACType::Ledger)
            {
                cont1+=['MainAccount','112140',2];
                cont1+=cont2;
                offsetledgerDim=AxdDimensionUtil::getLedgerAccountId(cont1);

                if(ledgerDim==0)
                {
                        offSetAcctPattern = ['112140','112140'];
                        offsetledgerDim = AxdDimensionUtil::getLedgerAccountId(offSetAcctPattern);
                }

                ledgerJournalTrans.OffsetLedgerDimension  = offsetledgerDim;
            }
            else
            {
                offsetledgerDim = DimensionStorage::getDynamicAccount( '000021',ledgerJournalTrans.AccountType);
                ledgerJournalTrans.OffsetLedgerDimension = offsetledgerDim;
                ledgerDimension +=cnt;
                ledgerDimension +=cont2;
                DimensionDefault = AxdDimensionUtil::getDimensionAttributeValueSetId(ledgerDimension);
                ledgerJournalTrans.OffsetDefaultDimension = DimensionDefault;
            }

            periodicoffsetAccount = offsetledgerDim;

            ledgerJournalTrans.CurrencyCode          = "USD";
            ledgerJournalTrans.AmountCurCredit       = 6000;
            ledgerJournalTrans.FreqCode              = PeriodUnit::Month;
            ledgerJournalTrans.FreqValue             = 1;

            credit = ledgerJournalTrans.AmountCurCredit;
            if (ledgerJournalTrans.validateWrite())
            {
                ledgerJournalTrans.insert();
            }

            ttscommit;

        }
        catch(Exception::Error)
        {
            info(strFmt('Catched an error in row: %1',ledgerJournalTrans.OffsetDefaultDimension));
        }
        info(strFmt('Periodic journal inserted %1',ledgerJournalTable.JournalNum));


        ////Line 2 Created
        try
        {
            ttsbegin;
            ledgerJournalTrans.clear();
            ledgerJournalTrans.initValue();
            ledgerJournalTrans.JournalNum   = ledgerJournalTable.JournalNum;
            ledgerJournalTrans.TransDate    = today();
            ledgerJournalName = ledgerJournalName::find(ledgerJournalTable.JournalName);
            periodicLedgerJournalId = ledgerJournalTrans.JournalNum ;
            select firstOnly numSeqTable
                where numSeqTable.RecId  == ledgerJournalName.NumberSequenceTable;
            if (numSeqTable)
            {
                numberseq = numberseq::newGetVoucherFromCode(numSeqTable.NumberSequence);
                ledgerJournalTrans.voucher = numberseq.voucher();
            }

            //ledgerJournalTrans.Voucher              = voucher;
            ledgerJournalTrans.AccountType          = LedgerJournalACType::Vend;
            ledgerJournalTrans.OffsetAccountType = LedgerJournalACType::Ledger;
            // Main account dimensions

            periodicACType = ledgerJournalTrans.AccountType;
            periodicOffSetACType = ledgerJournalTrans.OffsetAccountType;


            cont1=conNull();
            cont2=conNull();
            ledgerDimension =conNull();
            cont2 += ['BusinessUnit','082','Department','023'];
            cnt =2;
            if(ledgerJournalTrans.AccountType  == LedgerJournalACType::Ledger)
            {
                cont1+=['MainAccount','112100',2];
                cont1+=cont2;
                ledgerDim=AxdDimensionUtil::getLedgerAccountId(cont1);

                if(ledgerDim==0)
                {
                        offSetAcctPattern = ['112100','112100'];
                        ledgerDim = AxdDimensionUtil::getLedgerAccountId(offSetAcctPattern);
                }

                ledgerJournalTrans.LedgerDimension  = ledgerDim;
            }
            else
            {
                ledgerDim = DimensionStorage::getDynamicAccount( '000021',ledgerJournalTrans.AccountType);
                ledgerJournalTrans.LedgerDimension  = ledgerDim;
                ledgerDimension +=cnt;
                ledgerDimension +=cont2;
                DimensionDefault = AxdDimensionUtil::getDimensionAttributeValueSetId(ledgerDimension);
                ledgerJournalTrans.DefaultDimension = DimensionDefault;
            }

            periodicAccount = ledgerDim;
            cont1=conNull();
            cont2=conNull();
            ledgerDimension =conNull();
            cont2 += ['BusinessUnit','082','Department','023'];
            cnt =2;
            if(ledgerJournalTrans.OffsetAccountType  == LedgerJournalACType::Ledger)
            {
                cont1+=['MainAccount','112140',2];
                cont1+=cont2;
                offsetledgerDim=AxdDimensionUtil::getLedgerAccountId(cont1);

                if(ledgerDim==0)
                {
                        offSetAcctPattern = ['112140','112140'];
                        offsetledgerDim = AxdDimensionUtil::getLedgerAccountId(offSetAcctPattern);
                }

                ledgerJournalTrans.OffsetLedgerDimension  = offsetledgerDim;
            }
            else
            {
                offsetledgerDim = DimensionStorage::getDynamicAccount( '000021',ledgerJournalTrans.AccountType);
                ledgerJournalTrans.OffsetLedgerDimension = offsetledgerDim;
                ledgerDimension +=cnt;
                ledgerDimension +=cont2;
                DimensionDefault = AxdDimensionUtil::getDimensionAttributeValueSetId(ledgerDimension);
                ledgerJournalTrans.OffsetDefaultDimension = DimensionDefault;
            }

            periodicoffsetAccount = offsetledgerDim;

            ledgerJournalTrans.CurrencyCode          = "USD";
            ledgerJournalTrans.AmountCurCredit       = 4000;
            ledgerJournalTrans.FreqCode              = PeriodUnit::Month;
            ledgerJournalTrans.FreqValue             = 1;

            credit = ledgerJournalTrans.AmountCurCredit;
            if (ledgerJournalTrans.validateWrite())
            {
                ledgerJournalTrans.insert();
            }

            ttscommit;

        }
        catch(Exception::Error)
        {
            info(strFmt('Catched an error in row: %1',ledgerJournalTrans.OffsetDefaultDimension));
        }
        //info(strFmt('Periodic journal inserted %1',ledgerJournalTable.JournalNum));

    ledgerJournalTable.clear();
    //General Ledger create
    select firstonly   ledgerjournalname where LedgerJournalName.JournalName =='GenJrn';

    //create ledger journal table
    ledgerjournaltable.journalname      = ledgerjournalname.journalname ;
    ledgerjournaltable.initfromledgerjournalname();
    ledgerjournaltable.name             = " General Journal";
    genjourLedgerJournalId= ledgerjournaltable.JournalNum;

    ledgerJournalTable.insert();
    info(strFmt("General journal is %1",ledgerjournaltable.JournalNum));


    //ledgerJournalTrans1.clear();
    //ledgerJournalTrans1.initValue();

    //if(genjourLedgerJournalId)
    //{
       //ledgerJournalTrans = ledgerJournalTrans::find(periodicLedgerJournalId,ledgerJournalTrans.Voucher,true);
      while  select ledgerJournalTrans where ledgerJournalTrans.JournalNum==periodicLedgerJournalId
        {
       ttsBegin;
       ledgerJournalTrans1.initValue();
       ledgerJournalTrans1.data(ledgerJournalTrans);

       ledgerJournalTrans1.JournalNum=ledgerjournaltable.JournalNum;

        //ledgerJournalTrans1.initValue();

        select firstOnly numSeqTable
                where numSeqTable.RecId  == ledgerJournalName.NumberSequenceTable;
            if (numSeqTable)
            {
                numberseq = numberseq::newGetVoucherFromCode(numSeqTable.NumberSequence);
                ledgerJournalTrans1.voucher = numberseq.voucher();
            }

        if(!ledgerJournalTrans1.validateWrite())
        {
           throw error("ERROR");
        }
        else
        {
            ledgerJournalTrans1.insert();
        }

       ttsCommit;
        }



        //Post Journal
        ledgerJournalCheckPost      = ledgerJournalCheckPost::newLedgerJournalTable(ledgerJournaltable,Noyes::Yes);
        LedgerJournalCheckPost.run();

        //Lastdate updated
        while  select forUpdate ledgerJournalTrans where ledgerJournalTrans.JournalNum==periodicLedgerJournalId
        {
        ttsBegin;
        ledgerJournalTrans.LastTransferred=today();
        ledgerJournalTrans.update();
        ttsCommit;
        }


}

Split Ledger Account through x++

Some times when developing we encounter some strings of which we only need a segment of the string, let’s say for example the Ledger Account.

static void ledgeraccount(Args _args)
{
    GeneralJournalAccountEntry      gjae; //Table name
    container                                  con;
    List                                         list = new List(types::string);
    ListIterator                              iterator;
    str                                          ch;
    ;
    select gjae  where gjae.RecId == 5637151397;
    ch = strFmt("%1",gjae.LedgerAccount);//510500-002-022-007-Audio

//we will initialize the list using the standard method strSplit of Dynamics AX, we will use as the separator the “-” character without quotes.

    list = Global::strSplit(Ch, '-');

//Now we must start the iterator for our list.
//The iterator will loop through the lines of our list and them to a container which in our example will be “con”.

    iterator = new ListIterator(List);
    while(iterator.more())
    {
        con+=iterator.value();
        iterator.next();
    }
    info(conPeek(con,1));//510500
    info(conPeek(con,2));//002
    info(conPeek(con,3));//022
    info(conPeek(con,4));//007
    info(conPeek(con,5));//Audio

//Now we have a populated container and,  using the “conPeek” standard function we can retrieve the elements from the container by the index.
}

Wednesday, 25 May 2016

conversition of date to UTC DateTime

The DateTimeUtil class can be used to convert or modify utcdatetime and Timezone values.


static void Job39(Args _args)
{
    utcDateTime         rangeStart, rangeEnd;

    date               startDate, endDate;

    TimeOfDay           startTime, endTime;

    startDate   = 2\4\2011;       // day\month\year

    endDate     = 6\12\2012;       // day\month\year
    
    startTime   = str2time("1:22:59 am");     //GMT, NOT user time zone – this is how stored in the table

    endTime     = str2time("09:00:00 am");   
    
    rangeStart = DateTimeUtil::newDateTime(startDate,startTime,DateTimeUtil::getUserPreferredTimeZone());// apply user time zone to range
    
    rangeEnd   = DateTimeUtil::newDateTime(endDate,endTime,DateTimeUtil::getUserPreferredTimeZone());   
    
    info(strFmt("%1,%2",datetime2str(rangeStart),datetime2str(rangeEnd)));
}


The output will be































Thursday, 19 May 2016

Create and Post General Journal through x++

static void GeneralJournalCreateandPost(Args _args)
{
    LedgerJournalTable          jourTable;
    LedgerJournalTrans          jourTrans;
    LedgerJournalTableData      jourTableData;
    LedgerJournalTransData      jourTransData;
    LedgerJournalStatic         jourStatic;
    DimensionDynamicAccount     ledgerDim;
    DimensionDynamicAccount     offsetLedgerDim;
    LedgerJournalCheckPost      jourPost;
    ttsBegin;
    ledgerDim = DimensionStorage::getDynamicAccount('000001',LedgerJournalACType::Vend);
    offsetLedgerDim = DimensionStorage::getDynamicAccount('USMF OPER',LedgerJournalACType::Bank);
    jourTableData = JournalTableData::newTable(jourTable);
    jourTable.JournalNum = jourTableData.nextJournalId();
    jourTable.JournalType = LedgerJournalType::Payment;
    jourTable.JournalName = 'IntJrn';
    jourTableData.initFromJournalName(
    LedgerJournalName::find(jourTable.JournalName));
    jourStatic = jourTableData.journalStatic();
    jourTransData = jourStatic.newJournalTransData(
    jourTrans,
    jourTableData);
    jourTransData.initFromJournalTable();
    jourTrans.CurrencyCode = 'USD';
    jourTrans.initValue();
    jourTrans.TransDate = systemDateGet();
    jourTrans.AccountType = LedgerJournalACType::Vend;
    jourTrans.LedgerDimension = ledgerDim;
    jourTrans.Txt = 'Vendor payment journal demo';
    jourTrans.OffsetAccountType = LedgerJournalACType::Bank;
    jourTrans.OffsetLedgerDimension = offsetLedgerDim;
    jourTrans.AmountCurDebit = 1000;
    jourTransData.create();
    jourTable.insert();
    ttsCommit;
   //Post
    jourPost = LedgerJournalCheckPost::newLedgerJournalTable(jourTable,NoYes::Yes);
    jourPost.run();
    info(strFmt("Journal '%1' has been created", jourTable.JournalNum));

}

Monday, 9 May 2016

passing the number of records that are selected in the grid to another form control:

First of all  create  a new form "GridLinesCounter".
After that add the intedit control in that  form Design and change the property auto declaration to yes.
Create a new menu item and add this form to that menu item.

Go to the sales table list page form and add the created menu item in the ActionPane.
Then  override the clicked method in that menu item botton.

void clicked()
{
     FormDataSource fds;
    Common common;
    int counter;
    Args                args;
    FormRun             formrun;
    ;
    //super();
                     args = new Args();

    fdS = SalesTable_ds;
    for (common = fdS.getFirst(true) ? fdS.getFirst(true) : SalesTable_ds.cursor(); common; common = fdS.getNext())
    {
        counter++;
    }
    args.parm(int2str(counter));
    args.name(formstr(gridlinescounter));
    formRun = classFactory.formRunClass(Args);
    formRun.init();
    formrun.run();
    formrun.wait();
    info(int2str(counter));
}


Open the "GridLinesCounter" form and add init method.

public void init()
{
    str counter;
    counter = element.args().parm();
    super();
   intedit.value(str2int(Counter));
}
Now,go to salestablelistpage form and select some records .
Then click newmenuitem button (gridlinescounter) then a form will be opened showing the no of records selected.

-----------------------------------------------------------------
Another code to get the same result .
void clicked()
{
    int                 recordsCount;
    HcmPosition         hcmPosition1;
    container           con;
    Args                args;
    str                 multiSelectString;
    FormRun             formrun;
    args = new Args();
    // gets the total records selected
    recordsCount = HcmPosition_ds.recordsMarked().lastIndex();

    hcmPosition1= HcmPosition_ds.getFirst(1);

    while(hcmPosition1)
    {
        // storing recid of selected record in container
        con = conIns(con,1, hcmPosition1.RecId);
        // converting container to string with comma separated
        multiSelectString = con2Str(con,',');

        hcmPosition1= HcmPosition_ds.getNext(); // moves to next record
    }
    // passing string
    args.parm(multiSelectString);
    args.name(formstr(CH_RecrutmentForm));
    formRun = classFactory.formRunClass(Args);
    formRun.init();
    formrun.run();
    formrun.wait();
}

public void init()
{
    container con;
    int i;
    str multipleRecords;
    int record;
    super();
    // getting string value from caller
    multipleRecords = element.args().parm();
    // string to container
    con = str2con(multipleRecords,",");

     for(i = 1;i<= conLen(con) ;i++)
    {
           intedit.value(i);    
    }  
}

Tuesday, 26 April 2016

Import Export Model with ax 2012 R3
Models are logical group of elements like tables and classes. In AX 2012 elements can be group and store in the model file. Model files are easy to create, export and import and this can be uninstlled from system when not required.

Export an .axmodel file (Windows PowerShell)

  1. On the Start menu, point to All Programs, point to Administrative Tools, and then click Microsoft Dynamics AX Management Shell.
  2. At the Windows PowerShell command prompt, PS C:\>, type the following command, and then press ENTER.
 EXPORT Command Syntax:
      Export-AXModel –Model <name> -File <Filename.axmodel>
 Example:
    Export-AXModel -Model Ch_File -File C:\Test\Ch_File.axmodel

Import an .axmodel file (Windows PowerShell)

  1. On the Start menu, point to All Programs, point to Administrative Tools, and then click Microsoft Dynamics AX Management Shell.
  2. At the Windows PowerShell command prompt, PS C:\>, type the following command, and then press ENTER.

IMPORT Command Syntax:

Install-AXModel -File <Filename.axmodel> -Details

Example:

Install-AXModel -File C:\Test\Ch_File.axmodel -Details

Create a New Model 
Command Syntax:
New-AXModel -Model TestModel -Layer ISV
Links:

Friday, 22 April 2016

Overview

Number sequences are unique identifiers that can be associated with a master record so that they can be individually distinguished. They can be either formatted as alpha-numeric strings or simply as numbers.
Microsoft Dynamics AX 2012 provides an easy to implement framework to generate custom number sequences.

Scenario

As part of this tutorial, a custom number sequence will be generated for the Customer Groups setup form (Accounts receivable à Setup à Customers à Customer groups)

Steps

  1. First create a new Extended Data Type (EDT). Open AOT àData Dictionary à Extended Data Types
  2. Right Click on Extended Data Types and create a new EDT NumSeqDemoCustGroupNum of type String
  3. Set the properties as shown below

  4. Now go to AOT à Classes and open the NumberSeqModuleCustomer class by right clicking it and selecting View Code

  5. In the loadModule method, add the following code after the last line of code
  6. //customer group number
    //define the EDT
    datatype.parmDatatypeId(extendedTypeNum(NumSeqDemoCustGroupNum));
    //define its default propertiesdatatype.parmReferenceHelp(literalStr(“Unique number for customer group”));datatype.parmWizardIsContinuous(true);datatype.parmWizardIsManual(NoYes::No);datatype.parmWizardIsChangeDownAllowed(NoYes::No);datatype.parmWizardIsChangeUpAllowed(NoYes::No);datatype.parmWizardHighest(999999);datatype.parmSortField(27);
    //define its scope
    datatype.addParameterType(NumberSeqParameterType::DataArea, truefalse);this.create(datatype);

  7. Now, go to AOT à Jobs and create a new job loadNumSeqCustDemo
  8. Write the following code in the job and then run it
    static void loadNumSeqCustDemo(Args _args){
    //define the class variableNumberSeqModuleCustomer seqMod = new NumberSeqModuleCustomer();
    //load the number sequences that were not generatedseqMod.load();}

  9. Now, go to Organization administration à Common à Number sequences à Number sequences
  10. Click on Generate button in the New button group
  11. In the Setup number sequences wizard, Press Next
  12. In the Setup set different values for the number sequence like the format, highest value and lowest value
  13. Click Next
  14. In the last step, Click Finish to generate the number sequences
  15. The number sequence is generated and can be used on the Customer Groups form
  16. Open AOT à Data Dictionary à Tables à CustGroup
  17. Add a new String field and set the properties as follows
  18. Add the newly added field in the Overview field group
  19. Now go to Forms àCustGroup and restore the form. It will add the newly added field in the grid
  20. Write the following code on the Class declaration node
     NumberSeqFormHandler numberSeqFormHandler;

  21. Create a new method on the form and write the following code
    NumberSeqFormHandler numberSeqFormHandler(){
    if (!numberSeqFormHandler){
    //create a reference of number sequence form handler class specifying the         EDT, Data source name and the field of the table
    numberSeqFormHandler =NumberSeqFormHandler::newForm(NumberSeqReference::findReference(extendedtypenum(NumSeqDemoCustGroupNum)).NumberSequenceId, element,CustGroup_DS,fieldnum(CustGroup,CustGroupNumber));}return numberSeqFormHandler;
    }

  22. Override the close method of the form and write the following code
    public void close(){
    if (numberSeqFormHandler)
    {numberSeqFormHandler.formMethodClose();}
    super();}

  23. Override the create method on the CustGroup data source and add the following code
    public void create(boolean _append = false){
    element.numberSeqFormHandler().formMethodDataSourceCreatePre();
    super(_append);
    element.numberSeqFormHandler().formMethodDataSourceCreate(true);}

  24. Override the write method on the CustGroup data source and add the following code
    public void write(){
    super();
    element.numberSeqFormHandler().formMethodDataSourceWrite();}

  25. Override the validateWrite method on the CustGroup data source and add the following code
    public boolean validateWrite(){
    boolean ret;
    ret = super();
    ret = element.numberSeqFormHandler().formMethodDataSourceValidateWrite(ret) && ret;
    return ret;}

  26. Override the delete method on the CustGroup data source and add the following code
    public
    void delete()
    {
    element.numberSeqFormHandler().formMethodDataSourceDelete();
    super();}

  27. Override the linkActive method on the CustGroup data source and add the following code
    public
    void linkActive()
    {
    element.numberSeqFormHandler().formMethodDataSourceLinkActive();
    super();}

  28. Now go to Accounts receivable à Setup à Customers à Customer groups
  29. Create a new record. The number sequence is generated according to the format defined as shown below
 SEPTEMBER 24, 2014