Thursday, August 5, 2010

Creating New Inventory Dimension - Storage

AX has 8 standard inventory dimension here is the classification of these 8 dimensions

Inventory Item Dimensions
  1. Size
  2. Colour
  3. Configuration
Inventory Storage Dimensions
  1. Batch
  2. Serial
  3. Warehouse
  4. Location
  5. Pallet
Below is the list of objects that needs to be created or modified while creating a new inventory storage dimension. Please note that the list is not exhaustive enough but contains most of the objects that needs to be modified. Let us assume the name of the new dimension would be 'Test'
xtended Data Types


Following is the table specifying the EDTs that one may need to create for new storage dimension. Reference EDT section specifies which EDT to look at while creating new EDT.

EDT Name = InventTestId
Label = Test
Extends = SysGroup
Type = String
Reference EDT = InventLocationId

Tables

New table 'InventTest' : Look at the table InventLocation for reference and create a new table InventTest. Do not forget to create the field groups, indexes, properties similar to InventLocation. You can duplicate this table and change the required fields, methods, fields groups, indexes, propeties etc.

Table InventParameters : A new method 'numRefInventTestId' needs to be created. Take method 'numRefInventSerialId' for an example while creating this method.

Table InventDim : You will have to create a new field 'InventTestId'. Add this field to field groups, 'AutoReport', 'InventoryDimensions'. Create a new index 'TestIdx' with this field, Add this field InvenyTesId to index 'DimIdx'. Modify the following methods, take cue from code for other dimensions and add the relevant code. Methods are: 'dim2dimParm', 'dimParm2dim', 'emptyDimField', 'findDim', 'findOrCreate', 'formQueryAddDynaLink', 'isFieldIdItemDim', 'isFieldIdTransferReceiptMergable', 'isFieldIdTransferTransitReceiptMergable'.

Table InventDimParm : Add a new field 'InventTestIdFlag'. Add this field to following field groups: 'AutoReport', 'Fixedview', 'View'.

Table InventSum : Add a new method named 'inventTestId'. Take cues from 'inventSerialId' method in the table.

Table InventSumDateTrans : You will have to create a new field 'InventTestId'. Add this field to field groups, 'AutoReport', 'InventoryDimension'. Modify following methods: 'initFromInventDim', 'inventDim'.

Table InventSumDeltaDim : You will have to create two new fields named 'InventTestId', 'InventTestIdFlag'. Add the 'InventTestId' field to following groups : 'AutoLookup', 'InventDim'. Add 'InventTestIdFlag' field to following groups: 'InventDimFlags'. Modify following methods: 'initFromInventDim', 'initFromInventDimParm', 'initInventDim', 'initInventDimParm'.

Table InterCompanyInventDim : You will have to create a new field 'InventTestId'. Add this field to field groups: 'AutoReport', 'InventoryDimensions', 'TmpInventDimensions'. Add the field to following indexes: 'DimIdx'. Modify following methods: 'fromInventDim', 'toInventDim', 'dim2dimParm', 'dimParm2dim', 'formQueryAddLink'.

Table PBATreeInventDim : You will have to create two new fields named 'InventTestId', 'InventTestIdVar'. Add the 'InventTestId' field to following groups : 'AutoReport', 'AllFields', 'InventoryDimensions'. Add 'InventTestIdVar' field to following field group: 'InventoryDimensions'. Add a new method named 'inventTestId'. Take cues from 'inventSerialId' method in the table.
 
Macros

Following is the list of macros that may need to be modified  
  1. InventDimSelect 
  2. InventDimJoin 
  3. InventDimGroupAllFields 
  4. InventDimExistsJoin

 Classes 

  
New class AxInventTest : Run the class AxGenerateAxBC and select the table InventTest. This will create new AxBC class for InventTest table and you will have to resolve some errors.

Class NumberSeqReference_Inventory : The method 'loadModule' has to be modified to create a reference for 'Test'.

Class InventDimRenameValue : Add a method 'newInventTest'. Take cue from method 'newInventSerial' for definition of this new method.

Class InventDimTracking : Modify method 'initFromArgs'. Take an example of any of the inventory dimensions for changes.

Class AxInventDim : Add parm and set methods for InventTestId field. Take example of parmInventSerialId and setInventSerialId. Modify method setTableFields to make a call to setInventTestId method.

AxInventDim_PriceDiscTable : Add method setInventTestId. Take example of setInventSerialId for definition of this method.

Class InventDimFixedClass : Add following methods : 'parmInventTestIdFlag' - Take example from parmInventSerialIdFlag method and 'inventTestIdFlag' - Take example from inventSerialId flag method. Create a macro for InventTestId in ClassDeclaration (look at declarations for other dimensions). Modify method 'fieldId2Idx'.

Class TradeInterCompany : Modify method 'createTmpInventSum'.

Class PBALib : Modify method 'createInventDim'.

Apart from these classes there are many more classes that may need modifications like InventMovement, InventUpd and its child classes. InventOnhand and related classes etc. If you want to know more you can search for keyword 'InventSerial' in the classes node and find out.

  
Forms

   
Following new forms need to be created

InventTest : Similar to InventSerial.
InvenTestIdLookup : Similar to InventSerialIdLookup

Tuesday, July 6, 2010

Check Journal Balance - When you meet a problem of "do not balance", this break point will be very helpful.

Object:


\Classes\LedgerVoucherObject\updateTotals


Invoke Scenario:

When there is some problem about imbalance, this function will be very helpful to track why it is imbalance.


Operation Instance:



General ledger -> Journals -> General journal -> Create a new line -> Click Line -> add lines for journal -> Click button post -> post.


Explanation of codes:
private void updateTotals(LedgerTrans _ledgerTrans)
{
LedgerTrans ledgerTransTotals;
;
ledgerTransTotals.data(_ledgerTrans);
if (transDateTotals.find(ledgerTransTotals)) //line 13
{

ledgerTransTotals.AmountCur += _ledgerTrans.AmountCur;
ledgerTransTotals.AmountMST += _ledgerTrans.AmountMST; //line 16
ledgerTransTotals.AmountMSTSecond += _ledgerTrans.AmountMSTSecond;
ledgerTransTotals.Qty += _ledgerTrans.Qty;
transDateTotals.ins(ledgerTransTotals, true);

}
else //line 21
{
transDateTotals.ins(ledgerTransTotals);
}
}
“ledgerTransTotals” is used to accumulate all the transactions. If the transaction is the first transaction needs to be checked, it goes into line 13. Otherwise, it goes into line 21. The ledgerTransTotals.AmountMST at line 16 should be 0 when the last transaction has been added, or it will not be posted. And you will receive a infolog “The trasaction on voucher *** do not balance”

Post Journal - Illustrate the structure of LedgerJournalcheckPost\postJournal. It is called by most journals.

Object:  Classes\LedgerJournalCheckPost\postJournal

Invoke Scenario:

Most of the journals (including “General ledger”, “Payment journal”, “Invoice journal”, “Invoice register”, “Invoice approval journal”, etc.) will call this method to deal with the posting staff.

Operation Instance:


General ledger -> Journals -> General journal -> Create a new line -> Click Line -> add lines for journal -> Click button post -> post.


Explanation of codes:


while select ledgerJournalTrans order by Voucher, AccountType, RecId //line 99

where ledgerJournalTrans.JournalNum == ledgerJournalTable.JournalNum

{

……

while (ledgerJournalTrans.AccountNum

ledgerJournalTrans.AmountCurDebit

// line 316
ledgerJournalTrans.AmountCurCredite

{

if (!this.postTrans(……))

……

ledgerJournalTrans = this.ledgerJournalTransOffset(ledgerJournalTrans, // line357

swappedAcToPostTaxedFirst);

……

}

……

}

……

if (interCompanyCompanies.elements() > 0) //line 400

{

interCompanyCompaniesEnumerator = interCompanyCompanies.getEnumerator();

while (interCompanyCompaniesEnumerator.moveNext())
{
if (interCompanyJournalIds.exists(interCompanyCompaniesEnumerator.current()))
{
ok = this.postJournalInterCompany(……);
……
}
}
}
Instance: (General journal Form)

GL -> Journals -> General journals -> lines
Add two lines as following:
Account Debit Credit Offset account

11010 1000 12060(intercompany)

21125 200 40112

Line 99: The while loop contains all the lines created in the journal form. In this instance, the while loop will be execute twice. One is for “11010, Offset 12060”, another is for “21125, Offset 40112”.

Line 316: This while loop will be execute twice at most. One is for the Current line account, another is for the offset account. In the end of this loop line357, the ledgerJournalTrans will be changed to its offset account.

Line 400: The codes within the ‘if’ condition is used to post the legertrans for intercompany. In this instance, the while loop inside the ‘if’ condition will be executed once. Because there is only one intercompany record 12060.

Friday, June 25, 2010

Upgrade from AX3.0, AX4.0 to AX 2009

The steps below provide a high-level overview of the tasks that you must complete to upgrade from Microsoft Dynamics AX 3.0 to Microsoft Dynamics AX 2009.

Back up your existing database and application files.

Import two .xpo files from the installation media to assist with data upgrade.

UpgradeColumnList.xpo, for 32-bit to 64-bit RecId field conversion.


LeftJustified.xpo, for removing any trailing spaces from fields.


Note: To help improve performance, you can apply the LeftJustified.xpo on the database that you create in step 4 after you’ve used the Microsoft Dynamics AX DB Upgrade Preparation tool but before you start the Microsoft Dynamics AX 2009 AOS.


(Optional) To help improve performance, remove all user data and logs of Microsoft Dynamics AX 3.0. For example, clean up the SysDatabaseLog table.


Create an empty database for Microsoft Dynamics AX 2009 in SQL Server 2005.


(Optional) To help improve performance, set initial data and log file sizes so that they don’t increase while you perform the data upgrade process.


(Optional) To help improve performance, set the recovery model to Simple for the Microsoft Dynamics AX 2009 Database.


Run AXDBUpgrade.exe (The Microsoft Dynamics AX DB Upgrade Preparation tool). Note: To help improve performance, you can run this tool in Multithreaded mode. For example, to run this tool in 10 threads, enter AxDbUpgrade.exe P/10 at a command prompt.


(Optional) Apply the LeftJustify file imported in step 2 to the Microsoft Dynamics AX 2009 database created in step 4.


Back up your Microsoft Dynamics AX database. Your database is ready to be upgraded.
Run the Microsoft Dynamics AX 2009 Setup file from the installation media. During installation, select the database that you created in step 4.


Copy your upgraded customized file into the correct application directory.


Start the AOS.


Start the Microsoft Dynamics AX 2009 client. The Upgrade checklist is displayed automatically.


Complete the steps in the Upgrade checklist to finish upgrading.


The steps below provide a high-level overview of the tasks that you must complete to upgrade from Microsoft Dynamics AX 4.0 to Microsoft Dynamics AX 2009.


Back up your existing database and application files (AX 4.0 database and (*.aod, *.ahd, *.ald, *.add, *.khd files from Dynamics AX 4.0\Application\Appl folder; copy these files from configuration that you wants to be upgrade).

Before you upgrade, you must execute the following SQL script on your AX 4.0 database: 

--DIMENSIONCOLLECTION



UPDATE SQLDICTIONARY SET FIELDID=1 WHERE FIELDID=50002 AND TABLEID=2897;


UPDATE SQLDICTIONARY SET FIELDID=2 WHERE FIELDID=50005 AND TABLEID=2897;


UPDATE SQLDICTIONARY SET FIELDID=3 WHERE FIELDID=50007 AND TABLEID=2897;


UPDATE SQLDICTIONARY SET FIELDID=4 WHERE FIELDID=50008 AND TABLEID=2897;


--DIMENSIONHIERARCHYCOMBINATION


UPDATE SQLDICTIONARY SET FIELDID=1 WHERE FIELDID=50002 AND TABLEID=2898;


UPDATE SQLDICTIONARY SET FIELDID=2 WHERE FIELDID=50003 AND TABLEID=2898;


UPDATE SQLDICTIONARY SET FIELDID=3 WHERE FIELDID=50005 AND TABLEID=2898;


UPDATE SQLDICTIONARY SET FIELDID=4 WHERE FIELDID=50006 AND TABLEID=2898;


UPDATE SQLDICTIONARY SET FIELDID=5 WHERE FIELDID=50009 AND TABLEID=2898;


--DIMENSIONSETCOMBINATIONDUP2899


UPDATE SQLDICTIONARY SET FIELDID=1 WHERE FIELDID=50001 AND TABLEID=2899;


UPDATE SQLDICTIONARY SET FIELDID=2 WHERE FIELDID=50002 AND TABLEID=2899;


UPDATE SQLDICTIONARY SET FIELDID=3 WHERE FIELDID=50003 AND TABLEID=2899;


--DIMENSIONSETCOMBINATIONTEMP


UPDATE SQLDICTIONARY SET FIELDID=1 WHERE FIELDID=50001 AND TABLEID=2900;


UPDATE SQLDICTIONARY SET FIELDID=2 WHERE FIELDID=50002 AND TABLEID=2900;


UPDATE SQLDICTIONARY SET FIELDID=3 WHERE FIELDID=50003 AND TABLEID=2900;


UPDATE SQLDICTIONARY SET FIELDID=4 WHERE FIELDID=50004 AND TABLEID=2900;


UPDATE SQLDICTIONARY SET FIELDID=5 WHERE FIELDID=50005 AND TABLEID=2900;


UPDATE SQLDICTIONARY SET FIELDID=6 WHERE FIELDID=50006 AND TABLEID=2900;


--PROVISIONALHIERARCHY


UPDATE SQLDICTIONARY SET FIELDID=1 WHERE FIELDID=50001 AND TABLEID=2901;


UPDATE SQLDICTIONARY SET FIELDID=2 WHERE FIELDID=50002 AND TABLEID=2901;


UPDATE SQLDICTIONARY SET FIELDID=3 WHERE FIELDID=50007 AND TABLEID=2901; 



Run the Microsoft Dynamics AX 2009 Setup file from the installation media. During installation, select your existing Microsoft Dynamics AX database (don't start AOS service)

Go to AX instance location that you installed in last step, normally this location is in \Microsoft Dynamics\5.0\Application\Appl\ folder, create new folder named 'Old' and copy SYS and GLS (*.aod, *.ahd, *.ald, *.add, *.khd) files from AX 4.0 backup to this Old folder.

Back to the location \Microsoft Dynamics\5.0\Application\Appl\ and paste all AX 4.0 application files (*.aod, *.ahd, *.ald, *.add, *.khd ) from all layers above the LOS layer ( BUS, VAR, CUS, USR, and respective patch layers) to this location. Delete index file (axapd.aoi - if found) from this directory.


Start the Microsoft Dynamics AX 2009 client. The Upgrade checklist is displayed automatically.


Complete the steps in the Upgrade checklist to finish upgrading.

Tuesday, June 22, 2010

close* methods on a form

There are “only” 5 ways to close a form:
1. Close - close the form
2. CloseOK – close the form, and set the OK flag – called by the commandbutton: Ok
3. CloseCancel – close the form, and set the Cancel flag – called by the commandbutton: Cancel
4. CloseSelectRecord – close the lookup form, and set return record
5. CloseSelect – close the lookup form, and set return value

The methods in past-tense are used to determine if or how a form was closed:
6. Closed – The form is no longer open
7. ClosedOK – The form was closed by the user clicking ‘OK’
8. ClosedCancel – The form was closed by the user clicking ‘Cancel’

And canClose() is called before any of the close methods get called.

Monday, June 7, 2010

The New Dynamics AX 2011 X++ Editor

New features have already been added to the next version of Dynamics AX, Microsoft Dynamics AX 2011.
Some of the new features include:

1. Ability to see lines in code
2.Improved IntelliSense features (all possibilities will appear once you type)
3.Great ability to select words in editor without selecting the line from the beginning
4.More colors
5.Ability to check Labels value without going to the Label Editor
6... and many more.

Wednesday, May 26, 2010

Generic SysTableLookup Method

It is often needed to write a custom lookup method and the SysTableLookup class can be useful to create lookups from code. However the following method uses the SysTableLookup in the background but can be called easier.

When using the SysTableLookup class, for most of the simple lookups (1 datasource table) it is alway the same. You need the following :

TableId, LookupControl, LookupFields, ReturnFields, SortFields and sometimes the use of a tmpTable.

Now following method is a generic method to user the SysTableLookup class :
public static void doLookup(TableId             _tableId,
                            Container           _lookupFields,
                            Container           _sortFields,
                            FormStringControl   _control,
                            FieldId             _returnItemFieldNum,
                            Map                 _queryRanges    = null,
                            Boolean             _useTmpTable = false,
                            Common              _tmpBuffer = null
                            )
{
    SysTableLookup          sysTableLookup  = SysTableLookup::newParameters(_tableId, _control);
    Query                   query           = new Query();
    QueryBuildDataSource    qbds;
    int                     i;
    fieldId                 lookupFieldId;
    ;
 
    for(i=1;i <= conlen(_lookupFields);i++)
    {
        lookupFieldId = conPeek(_lookupFields, i);
 
        if(lookupFieldId == _returnItemFieldNum)
            sysTableLookup.addLookupfield(lookupFieldId, true);
        else
            sysTableLookup.addLookupfield(lookupFieldId);
    }
 
    qbds = query.addDataSource(_tableId);
 
    for(i=1;i <= conlen(_sortFields);i++)
    {
        qbds.addSortField(conPeek(_sortFields, i));
    }
 
 
    if(_queryRanges)
    {
        rangeEnumerator = _queryRanges.getEnumerator();
 
        while (rangeEnumerator.moveNext())
        {
            qbds.addRange(rangeEnumerator.currentKey()).value(any2Str(rangeEnumerator.currentValue()));
        }
    }
    if(_useTmpTable)
        sysTableLookup.parmTmpBuffer(_tmpBuffer);
 
    sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();
}

Now when you want to create a lookup you can do it easier by doing the following :
public void lookup()
{
    Container   fieldNums       = [FieldNum(CustTable, AccountNum), FieldNum(CustTable, Name)];
    Container   sortFields      = [FieldNum(CustTable, AccountNum)];
    FieldId     returnFieldId   =  FieldNum(CustTable, AccountNum);
    Map         queryRanges     = new Map(Types::Integer, Types::String);
    ;
    queryRanges.insert(FieldNum(CustTable, AccountNum), '4000');
    LIBSysTableLookup::doLookup(TableNum(CustTable), fieldNums, sortFields, this, returnFieldId, queryRanges);
}

So the only thing you need to do is specify the fields, returnfields and sortfields…

Ans let’s look at the following example : We need a lookup with a temporary table. Then we can do it like this :
Container   fieldNums       = [FieldNum(TmpIdRef, Name), FieldNum(TmpIdRef, HelpTxt)];
    Container   sortFields      = [FieldNum(TmpIdRef, Name)];
    FieldId     returnFieldId   = ConPeek(fieldNums, 1);
    TmpIdRef    tmpTable;
    ;
    tmpTable = LIBDifferenceAction::BuildActionClassList();
 
    XYZSysTableLookup::doLookup(TableNum(TmpIdRef), fieldNums, sortFields, this, returnFieldId, true, tmpTable);