“[BPUnusedStrFmtArgument]:The placeholder ‘%1’ to strFmt is not used in the format string.”

to remove the warning add literalStr() for label string validation.

Where the label has “Item length: %1”

warning( strFmt( literalStr("@xxx:xyxyxy"), inventDim.InventColorId ) );
Posted in Dynamics Ax2009 | Leave a comment

msvsmon.exe error

  1. Update Visual studio to the latest version using VS Installer.
  1. Unchecked the “Enable Just my code” property on Debugging options

Good to go now…

Posted in Dynamics Ax2009 | Leave a comment

SQL cleanup space

Please run the following SQL script on each copy of your AX instance, transaction database. This should release around 45 GB of disk space from your database.

 

use DEV

 

truncate table BATCHJOB;

truncate table BATCH;

truncate table BATCHJOBALERTS;

truncate table BATCHSERVERGROUP;

truncate table BATCHHISTORY;

truncate table RSAADPCalculationDetail;

truncate table AIFDocumentLog;

truncate table AIFMessageLog;

 

DBCC SHRINKFILE (N’AXCNFGCU8′ , 44723)

GO

 

You need to change the USE statement to your database instance.

Posted in SQL Server | Leave a comment

Resetting Production order status

On recent enhancement there was a scenario that for some condition I need to reset the production order status from Estimated/Scheduled to created and need to delete the production order. The reference to this production order also should be removed from sales order.

 

I wrote the following code

Try

{

ttsBegin;

ProdTable = prodtable::find(_prodId, true);

If (prodTable)

{

prodTable.prodStatus = ProdStatus::created;

if (prodTable.validateWrite())

prodTable.update;

}

ttscommit;

}

Catch(exception::error)

{

checkFailed(strFmt(@”Delete of Production order %1 is failed.”, _prodId));

 

}

 

 

after resetting this I deleted the production order and it deletes the coproduct records too.

 

I thought it worked fine. But actually it deletes the Production line reference from inventory transaction and not co-product reference from inventory transaction.

So I debugged more and I found the right code which deletes all the references related to production order from transaction.

 

This below code deletes all the inventory transaction related to production order when we change the status to created.

 

Public static void resetProdStatus(prodId _prodId)

{

ProdMultiStatusDecrease       prodMultiStatusDecrease;

ProdParmStatusDecrease      prodParmStatusDecrease;

ProdTable                             prodtable;

Args                                     args    = new Args();

;

 

Try

{

ttsbegin;

prodTable = ProdTable::find(_prodId,true);

 

if (ProdTable.ProdStatus > prodStatus::Created)

{

args.record(ProdTable);

 

select prodParmStatusDecrease where prodParmStatusDecrease.ProdId == ProdTable.ProdId;

 

if (!prodParmStatusDecrease.RecId)

 

{

 

prodParmStatusDecrease.clear();

 

prodParmStatusDecrease.initFromProdTable(ProdTable);

 

prodParmStatusDecrease.WantedStatus = ProdStatus::Created;

 

prodParmStatusDecrease.ParmId = NumberSeq::newGetNum(CompanyInfo::numRefParmId()).num();

 

prodParmStatusDecrease.insert();

 

}

 

prodMultiStatusDecrease = prodMultiStatusDecrease::construct(args);

 

prodMultiStatusDecrease.initParmBuffer(prodParmStatusDecrease);

 

prodMultiStatusDecrease.parmId(prodParmStatusDecrease.ParmId);

 

prodMultiStatusDecrease.run();

 

}

ttsCommit;

 

}

Catch (Exception::error)

{

checkFailed(strFmt(@”Delete of Production order %1 is failed.”, _prodId));

}

 

}

 

Hope it helps.

Posted in AX 2012 | Leave a comment

Open Listpage from Infolog

Here is the scenario where user wants to open the Listpage from a infolog. This can be achieved by SysInfoAction class.

 

static void infoSO(Args _args)
{
Query q = new Query(queryStr(SalesTableListPage));
SalesId salesorders;
salesTable salestable;

while select salestable where salestable.salesStatus == SalesStatus::cancelled
{
salesOrders += salesTable.salesid + “,”;
}
Salesorders = strdel(salesorders,strlen(salesorders)-1,1);

q.dataSourceTable(tableNum(SalesTable)).addRange(
fieldNum(SalesTable, salesId(salesid));

info(‘Click Show to open list page’, ”, SysInfoAction_FormrunQuery::newFormnameQuery(formStr(SalesTableListPage), q));
}

Posted in AX 2012 | Leave a comment

COC on Class methods

Chain of command:

On platform update 9 of Dynamics AX for Operations, we have a new extension possibility called chain of command (CoC). Now we are able to add pre and post functionality to extensible methods in a much easier and readable manner than the previously used event handlers we are now able to access protected methods and variables directly in the extended class without problems.

 

In other words, it allow developers to wrap logic around methods defined in a base class. This allows extending the logic of public and protected methods without the need to use event handlers.

 

Now let us check how it works with an example.

 

Let us take class as an example.

 

Condition:

The method should exists in the Class for which you are going to use CoC.

 

For demo Iam taking salesLinetype\ initvalue method. Here I need to assign some default value into the sales line table while creating sales line. Since standard class methods cannot be modified, we need to create either Pre-handler or Post-Handler method to achieve this. Instead of writing event handler COC comes into picture where we can achieve this in single method.

 

Create a new SalesLineTypeClass_extension. Final should be prefix. Above the class specify the Extensionof Keyword followed by Type of Extension [Class/form] and Name of the object[Class / Form] .

 

We use exactly the same notation as the original method we are extending and add a mandatory “next” keyword to the call, which will wrap our extension code around the extended method. This next keyword separates the pre and post parts of our extension and mandatory to be called inside the chain of command method.

Note: Next call cannot be placed in any kind of program block like if() block or while block.

 

When you call next(), it checks for other extensions in the queue and runs them in random order, lastly running the base code.

 

The code before next initvalue () will work as pre handler of initvalue method.

The code after next initvalue () will work as post handler of initvalue method.

 

 

Here there is an issue in assignment statement. We cannot get the sales line reference from Standard class.

 

To achieve this we have two options:

  1. If saleslinetype class has parm() method that returns sales line, we can use it

[ExtensionOf(classstr(SalesLineType))]

final class SalesLineType_Extension

{

void initValue()

{

this.parmsalesLine().SalesQty   = 5;//Pre handler

next initvalue();

this.parmsalesLine().SalesQty   = 10;//Post handler

}

 

2. create a new method like getSalesline() which will return this.salesline;

 

[ExtensionOf(classstr(SalesLineType))]

final class SalesLineType_Extension

{

 

public Salesline getsalesLine()

{

return this.salesLine;

}

 

void initValue()

{

this.getsalesLine().SalesQty   = 5;//works like Pre handler

next initvalue();

this.getsalesLine().SalesQty   = 10;//works like Post handler

}

 

}

output:

 

Create a salesline and check the sales qty will be defaulted to 10 if code written after next else it should be 5 or standard 1 qty.

 

Posted in D365 | Leave a comment

Remove Special Characters

Here is a way to remove special characters from a string.

static void RemoveAllSpecialChararcters(Args _args)
{
str sometext = “ABC#DE%F_$#G@1&23″;

str x = System.Text.RegularExpressions.Regex::Replace(sometext, @”[#,_,$,%,@,&]”, “”);
info(x);
}

 

Output: ABCDEFG123

 

Posted in AX 2012 | Leave a comment

TFS: Not Sync.

I found some useful job and sharing it in my blog which will be used for developers.When we do full sync. some of the objects will not be sync. properly. Object information will be shown in Synchronization log form. Run the following job which will combine each object type and will give the Number(batch Num) which needs to execute individually.

static void updateNotSynced(Args _args)

{

SysVersionControlSynchronizeLog         syncLog;

SysVersionControlSynchronizeBatchNum    lastNum;

boolean                                 entered = false;

//find last batch num

select firstOnly BatchNum from syncLog

order by syncLog.BatchNum desc;

lastNum = syncLog.BatchNum;

setPrefix(‘Numbers to process:’);

//classes

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Classes*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for classes is: %1’, lastNum));

}

//forms

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Forms*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Forms is: %1’, lastNum));

}

//tables

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Data dictionary*Tables*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Tables is: %1’, lastNum));

}

//extended data types

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Data dictionary*Extended data types*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for EDTs is: %1’, lastNum));

}

//base enums

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Data dictionary*Base enums*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Enums is: %1’, lastNum));

}

//menu items

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Menu items*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Menu items is: %1’, lastNum));

}

//shared projects

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Projects*Shared*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Shared projects is: %1’, lastNum));

}

//jobs

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Jobs*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Jobs is: %1’, lastNum));

}

//SSRS Reports

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*SSRS Reports*Reports*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for SSRS reports is: %1’, lastNum));

}

//Security roles

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Security*Roles*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Roles is: %1’, lastNum));

}

//Security duties

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Security*Duties*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Duties is: %1’, lastNum));

}

//Security privileges

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Security*Privileges*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Privileges is: %1’, lastNum));

}

//Menus

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Menus*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Menus is: %1’, lastNum));

}

//Services

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Services*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Services is: %1’, lastNum));

}

//Code permissions

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Security*Code permissions*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Code permissions is: %1’, lastNum));

}

//Workflow

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Workflow*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Workflows is: %1’, lastNum));

}

//Parts

ttsBegin;

while select forUpdate syncLog

where syncLog.Processed == NoYes::No &&

syncLog.ItemPath  like ‘*Parts*’

{

syncLog.BatchNum = lastNum + 1;

syncLog.update();

entered = true;

}

ttsCommit;

if (entered)

{

lastNum++;

entered = false;

info(strFmt(‘Batch number for Parts is: %1’, lastNum));

}

}

Posted in AX 2012 | Leave a comment

Reset Production order status through x++ code

On recent enhancement there was a scenario that for some condition I need to reset the production order status from Estimated/Scheduled to created and need to delete the production order. The reference to this production order also should be removed from sales order.

 

I wrote the following code

Try

{

ttsBegin;

ProdTable = prodtable::find(_prodId, true);

If (prodTable)

{

prodTable.prodStatus = ProdStatus::created;

if (prodTable.validateWrite())

prodTable.update;

}

ttscommit;

}

Catch(exception::error)

{

checkFailed(strFmt(@”Delete of Production order %1 is failed.”, _prodId));

 

}

after resetting this I deleted the production order using delete_from and it deletes the coproduct records too.

 

I thought it worked fine. But actually it deletes the Production line reference from inventory transaction and not co-product reference from inventory transaction. Filter the production order that was reset recently in IM > Inquiries > Transaction. you can see the co-product reference is not deleted.

So I debugged more and I found the right code which deletes all the references related to production order from transaction.

This below code deletes all the inventory transaction related to production order when we change the status to created.

 

Public static void resetProdStatus(prodId _prodId)

{

ProdMultiStatusDecrease      prodMultiStatusDecrease;

ProdParmStatusDecrease     prodParmStatusDecrease;

ProdTable                              prodtable;

Args                                     args   = new Args();

;

 

Try

{

ttsbegin;

prodTable = ProdTable::find(_prodId,true);

 

if (ProdTable.ProdStatus > prodStatus::Created)

{

args.record(ProdTable);

 

select prodParmStatusDecrease where prodParmStatusDecrease.ProdId == ProdTable.ProdId;

 

if (!prodParmStatusDecrease.RecId)

 

{

prodParmStatusDecrease.clear();

prodParmStatusDecrease.initFromProdTable(ProdTable);

prodParmStatusDecrease.WantedStatus = ProdStatus::Created;

prodParmStatusDecrease.ParmId = NumberSeq::newGetNum(CompanyInfo::numRefParmId()).num();

prodParmStatusDecrease.insert();

}

prodMultiStatusDecrease = prodMultiStatusDecrease::construct(args);

prodMultiStatusDecrease.initParmBuffer(prodParmStatusDecrease);

prodMultiStatusDecrease.parmId(prodParmStatusDecrease.ParmId);

prodMultiStatusDecrease.run();

}

ttsCommit;

}

Catch (Exception::error)

{

checkFailed(strFmt(@”Delete of Production order %1 is failed.”, _prodId));

}

}

Posted in AX 2012 | 1 Comment

Removing Trailing zero’s from decimal places

I came across a scenario where customer need to remove the trailing zero’s in decimal places if exists. Since Ax doesn’t have the functions to remove , I created a new method which will remove the zeros.

Public void RemoveTrailingZeros(args _args)

{

str txt = ‘0.1823’;

str ch = ‘0’;

str result;

str tmp;

int i = strLen(txt);

while(true)

{

tmp = subStr(txt, i, 1);

if(i && tmp == ch)

{

i–;

}

else

{

break;

}

}

result = strDel(txt, i+1, maxInt());

info(result);

}

I have set no. of decimal places to 4.

 

Example 1:

Str       txt = ‘0.1800’;

Result : 0.18

 

Example 2:

Str       txt = ‘0.1850’;

Result : 0.185

Example 3:

Str       txt = ‘0.1854’;

Result : 0.1854

Posted in AX 2012 | Leave a comment