Friday 9 March 2012

This website is very use full EP and also .net and ax

http://dynamics-ax-dev.blogspot.in/2010/04/retrieving-control-values-from-existing.html

Using the .NET Business Connector to Export Sales Orders with Multiple Sales Lines into AX from a .NET Application: Part 2

Expanding on the previous blog, let’s say that another requirement has been added, which is, to add the ability to track the date that a record was imported into the system, which will be used to prevent duplicate records for a given customer in a given month from being imported.

The first step would be to add an ImportDate field in the SalesTable via the AOT

The second step would then be to modify our class (ImportToAX) method (ImportSalesOrder) to accept an import date.

The third step would then be to modify our class (ImportToAX) method (ImportSalesOrder) to include logic to determine if a duplicate record (a given customer in a given month) already exists. Programming instinct coupled with my novice skills in AX development tell me that in order to determine if we already have a record for a given customer in a given month, I would add the following lines into our X++ class (ImportToAX) method (ImportSalesOrder):




Select count(RecId) From salesTable
where salesTable.CustAccount == CustAccount && mthofyr(salesTable.ImportDate) == mthofyr(ImportDate) && year(salesTable.ImportDate) == year(ImportDate);
ret = salesTable.RecId;

if (ret == 0)
{
………
}
else
{
throw Global::error("Only one record is allowed per customer in a given month!");
}


This however is invalid code, which throws two errors when compiled. The first being:

Illegal use of WHERE expression

This error is thrown, apparently because methods cannot be used in a where clause, and since I have attempted to use the mthofyr() and year() methods within my where clause, we have an issue. Therefore, one possible way of getting around this, is to take a different approach, such as the following valid code:

found = false;

while select salesTable where salesTable.CustAccount == CustAccount
{
if (mthofyr(salesTable.ImportDate) == mthofyr(ImportDate) && year(salesTable.ImportDate) == year(ImportDate)) found = true;
}

if (!found)
{
………
}
else
{
throw Global::error("Only one record is allowed per customer in a given month!");
}

The second error that we get:

Container and unbounded string (text) fields are not allowed in a WHERE expression

This is inherently related to our method definition, where the CustAccount parameter is defined as an str:

str ImportSalesOrder(str CustAccount, real Total, real Taxes, real Fees, date ImportDate)
{
……
}

The problem is that the salesTable.CustAccount field is actually defined as the extended data type, CustAccount, which extends the base type str. Because AX is a bit finicky, a standard str type cannot be compared to an extended data type (even though the extended data type extends the base type we are comparing to). Therefore, the simplest solution is to make our incoming CustAccount parameter of type CustAccount.

str ImportRoyaltyReport(CustAccount CustAccount, real Total, real Taxes, real Fees, date ImportDate)
{
……
}


This actually has no ill affect the .NET side of the project. In fact, the only parts of our .NET function needing change would be first in the function definition:

static public bool ImportOrder(string CustomerAccount, decimal Total, decimal Tax, decimal Fees, DateTime ImportDate)

And then the code to pass in the additional Import Date parameter to the AX method call:

object[] param = new object[5];
param[0] = CustomerAccount;
param[1] = Total;
param[2] = Tax;
param[3] = Fees;
param[4] = ImportDate;
Object retval = Import.Call("ImportSalesOrder", param);


Finally, to reduce code redundancy in our AX class (ImportToAX) method (ImportSalesOrder), the method could be compacted to avoid having the same block of code repeated 3 times (as in Part 1). Here we can use a couple additional variables, a loop, and a switch statement, which will transform our method as whole to look like the following:

str ImportSalesOrder(CustAccount CustAccount, real Total, real Taxes, real Fees, date ImportDate)
{

SalesTable salesTable;
SalesLine salesLine;
InventDim inventDim;
NumberSeq NumberSeq;

str retval;
int line;
str line_item;
real line_amt;
boolean found;
;

retval = "";

found = false;

while select salesTable where salesTable.CustAccount == CustAccount
{
if (mthofyr(salesTable.ImportDate) == mthofyr(ImportDate) && year(salesTable.ImportDate) == year(ImportDate)) found = true;
}

if (!found)
{

// Generate the next SalesId (which is a Number Sequence)...

NumberSeq = NumberSeq::newGetNumFromCode(SalesParameters::numRefSalesId().numberSequence);
salesTable.SalesId = NumberSeq.num();

// Create the Sales Order...

salesTable.initValue();
salesTable.CustAccount = CustAccount;
salesTable.deliveryDate = today();
salesTable.PurchOrderFormNum = "Imported Data";
salesTable.Tmt_RoyaltyImportDate = ImportDate;

salesTable.initFromCustTable();

salesTable.insert();

// Create the 3 Sales Lines...

for (line = 1; line <= 3; line++) { switch(line) { case 1: line_item = "Total"; line_amt = Total; break; case 2: line_item = "Taxes"; line_amt = Taxes; break; case 3: line_item = "Fees"; line_amt = Fees; } salesLine.clear(); salesLine.SalesId = salesTable.SalesId; inventDim = salesLine.inventDim(); inventDim.InventSiteId = "01"; salesLine.setInventDimIdFromInventDim(inventDim); salesLine.ItemId = line_item; salesLine.SalesQty = 1; salesLine.SalesUnit = 'EA'; salesLine.SalesPrice = line_amt; salesLine.LineAmount = line_amt; salesLine.createLine(NoYes::No, NoYes::Yes, NoYes::No, NoYes::No, NoYes::No, NoYes::No); } retval = salesTable.SalesId; } else { throw Global::error("Only one record is allowed per customer in a given month!"); } return retval;

Corrupted Database? Think Again! It Might Simply Be a Corrupted Layer (aod) File

Corrupted Database? Think Again! It Might Simply Be a Corrupted Layer (aod) File.




Recently we had what appeared to be a major issue occur on our Development AX environment. After performing a Synchronize on the Data Directory in the AOT, we received several warning messages, and then when attempting to view various forms we were receiving SQL errors, and what appeared to be missing data.

The initial assumption was that the Database had become corrupted. So we went through the process of doing a backup of the database in our Testing AX environment (which had no issues), and restoring it to the Development AX environment. After the restore however, we still received the same errors as before, which had us puzzled for a moment. Then my colleague, Tim Golisch, remembered something very important.

Not everything in AX is stored in the Database, in fact, everything relating to the layers, are actually stored in AOD files, which reside in the: C:\Program Files\Microsoft Dynamics AX\50\Application\Appl\[DB NAME] folder.

So I stopped the AOS, removed the axuser.aod file, started the AOS, opened the client, and wala! Everything was back to normal

Thursday 1 March 2012

If You Need Runbase batch

1).dialog
2)getfromdialog
3)pack
4)unpack

1).Class declaration
str Name;
Dialogfield dfName;

//2).Cangobatchjournal
// True //return false means Batch Tab no need

3) dialog
;
dfName = dialog.addfieldvalue(types::string,Name);
return dialog;

4).getfromdialog
{
Name =dfName.value();
return super();
}

5)pack

6)unpack

7)run
Table t;
;
Runbasetable.Name =Name;
Runbasetable.insert();
EX:- Tutorial_Runbasebatch(class)
Imp methods:-
1)Main

2)Dialog

3)Getfromdialog

4)pack

5)unpack

6)cangobatchjournal

7)construct

8)run

9)discription

Dialogs

1) if You have 6-8 Unbound controls then we are creating Dialogs

2)Ok and Cancel Buttons are by defult on dialogs

3){
Dialog d = new Dialog("I am dialog ex");
Dialogfield dfName ,dfAccno;
;
dfName = d.addfield(Type::string ,"Name-lable",Name of the person-heldtext);
dfAccno = d.addfield(Typeid(CustAccno-EDT));
if(d.run())
{
info(dfName.value());
info(dfAccno.value());
}
else
{
throw error("");
}
}

Form calling sequence

1).when form is getting closed:
canclose method get call - can close return boolean true then only close method gets called
SQ:- Canclose()-Close().

2)Sequence of closing form using Ok command Button
SQ:- CloseOk()-Canclose()-Close.
Cancel command Button - save record property should be set to "NO".

3)Sequence of using Command button Cancel
SQ:-ClosedCancel()-Canclose()-Close().

4).When You Create a new record Using "Ctrl+N"
SQ:- Create of DS- Initvalue() of DS -Initvalue() of Table.

5)When user tries to delete a record from The Form
SQ:-Validate delete() of DS- Validate delete () of Table -Delete() of DS- Delete() of Table

6).Any critical Validation for The form alone
SQ:-Write The logic in The Validatedelete() of DS

7).When a record is Saved from the form
SQ:-Validatewrite() of DS- Validate write() of table- write() of ds -Write of Table() -Insert /Update of Table .

Enable/disable form controls (Active method)

1).From controls
purchline_Assettagno_ss3.enabled(false);
purchline_Assettagno_ss3.enabled(true);
2). we Can enable/disable buttons also write in initvalue/active method
if(cust.age>20)
{
Button .enabled(false);
}
else
{
Button.enabled(true);
}

Filteration Basedon check box yes::no

1)Datasource Execute query:-
this.query().dataSourceTable(tablenum(PurchTable)).addRange(fieldnum(PurchTable,Processed_S3_FM)).value(queryValue(noYes::Yes));
super();
2).Write
PurchTable.Processed_S3_FM=noYes::Yes;

Wednesday 4 January 2012

After creating forms or tables checking best practices

Select that Tables/Forms right click Add-Ins in that select check Best practices.

Monday 2 January 2012

Ax Technical


static void EndNodes(Args _args)
    {

       TreeNode    objTreeNode,objTreeNode1,objTreeNode2;
       int a,i,b;
       objTreeNode = TreeNode::findNode(@"\Menus\AccountsReceivable\Reports");
       a = objTreeNode.AOTchildNodeCount();
       if (objTreeNode)
        {
            objTreeNode = objTreeNode.AOTfirstChild();
            /*
            change objTreeNode object properties
            */info(strFmt("%1",a));
           while (objTreeNode)
            {
                for(i=1;i<=a;i++)
                {
                    b=0;
                    // info(objTreeNode.treeNodeName());
                    objTreeNode2 = objTreeNode.AOTfirstChild();
                    b = objTreeNode2.AOTchildNodeCount();
                    objTreeNode = objTreeNode.AOTnextSibling();
                    while (objTreeNode2)
                    {
                        if(b>0)
                        {
                            objTreeNode1 = objTreeNode2.AOTfirstChild();
                            while(objTreeNode1)
                            {
                                info(objTreeNode1.treeNodeName());
                                objTreeNode1 = objTreeNode1.AOTnextSibling();
                            }
                        }
                        else
                        {
                            info(objTreeNode2.treeNodeName());
                        }
                        objTreeNode2 = objTreeNode2.AOTnextSibling();
                }
            }

        }
    }
  }