Move Dynamics AX database to different Domain/machine.


How to move database from Machine 1 to Machine 2, they both have different User and Domain ?

Steps are very simple:

1. Attached the database,
2. Add your AX login to the database you attached.
3. Open the “userinfo” table from sql server
4. Find the row with ‘Admin’ Id
5. Update the following columns
5.1 SID with your machine SID
5.2 NetworkDomain with your network domain,
5.3 NetworkAlias with your AX logged in user.
6. Now start the AX

First ways to get SID using registry path.
If you dont know how to get the SID, Here are the steps for this too.

The SID can be fetched from registry editor. for this open command prompt from Start manu, type “Regedit” and press enter key.

Please note in the above mentioned window (Registry Editor) in the path specified path : HKEY_USERS\S-1-5-21-1494175365-1026638594-2087099728-XXXX.. This first big key is your user’s SID

Second ways to get SID is using the Ntdsutil command line util,

Applies To: Windows Server 2003, Windows Server 2003 R2, Windows Server 2003 with SP1, Windows Server 2008, Windows Server 2008 R2

Ntdsutil.exe is a command-line tool that provides management facilities for Active Directory Domain Services (AD DS) and Active Directory Lightweight Directory Services (AD LDS). You can use the ntdsutil commands to perform database maintenance of AD DS, manage and control single master operations, and remove metadata left behind by domain controllers that were removed from the network without being properly uninstalled. This tool is intended for use by experienced administrators.

Ntdsutil.exe is built into Windows Server 2008 and Windows Server 2008 R2. It is available if you have the AD DS or the AD LDS server role installed. It is also available if you install the Active Directory Domain Services Tools that are part of the Remote Server Administration Tools (RSAT).

1. Go to Run > cmd
2. Type ntdsutil and press Enter
3. ntdsutil prompt opens (ntdsutil: )
4. Type group membership evaluation and press Enter
5. Group membership evaluation prompt opens
6. Type run DOMAIN  and press Enter
7. A .tsv file will be created in C:\Documents and Settings\ OR .DOMAIN
8. Open .tsv file and copy the first SID appear in the file OR the SID associated to your User Name

Open document handling (DocuView) for other datasource/table than caller


Open document handling (DocuView) for other datasource/table than caller

Sometimes there’s requirement to open document handling from one form to shows the documents for other datasource/table.

Eg. From Purchase order form, open the document handling of the vendor (VendTable) instead of for the purchase order (PurchTable).

It can be achieved with the following 4 steps:

  1. Add the related table as datasource in the form
  2. Add a boolean global variable to ‘ClassDeclaration’
  3. Overwrite the method ‘docCursor’
  4. Add a button and overwrite the ‘clicked’ method

1. Add the related table as datasource in the form

2. Add a boolean global variable to ‘ClassDeclaration’
class FormRun extends ObjectRun
{
boolean      vendDoc;
}

3. Overwrite the method ‘docCursor’
public Common docCursor()
{
Common docCursor;
;

docCursor = super();

if(vendDoc)
docCursor = vendTable;

return docCursor;
}

4. Add a button and overwrite the ‘clicked’ method
void clicked()
{
super();

vendDoc = true;

if (!infolog.docu().isDocuViewSet())
infolog.docu().note(element);
else
infolog.docu().setActive();

vendDoc = false;
}

Save Last Value on on Form Form


Use pack/unpack on Form

If you have used runbase classes, you may be impressed by its pack and unpack mechanism. It allows users to keep the input values of last time. If you want to implement the same mechanism on the Form, it is easy as well:
Besides Pack/Unpack, add these six methods:
public dataAreaId lastValueDataAreaId()
{
return curExt();
}

private UserId lastValueUserId()
{
return curuserid();
}

private UtilElementType lastValueType()
{
return UtilElementType::Form;
}

private IdentifierName lastValueElementName()
{
return this.name();
}

private IdentifierName lastValueDesignName()
{
return ;
}

//this is called when no last value is retrieved
void initParmDefault()
{
}

further, in Close method of the form:
public void close()
{
super();
//add saveLast method after super()
xSysLastValue::saveLast(this);
}

in init method of the form:
public void init()
{
;

    //Add getLast method before super()
xSysLastValue::getLast(this);
super();

}

Create a new method in runtime


Create a new method in runtime

Some one may need to use codes to create or edit a method in Axapta.
Here is an example to show how to create a lookup method for a form’s field in runtime.

    static void CreateFieldMethod(Args _args)
{

TreeNode tn1,tnAddr, methodsNode;
MemberFunction memberFunction;
str source;
;
        tn1 = infolog.findNode(\Forms\Address\Data Sources\Address\Fields\AddrRecId”);

tnAddr = infolog.findNode(
\Forms\Address );
methodsNode = tn1.AOTfindChild( ‘Methods’ );
methodsNode.AOTadd(‘lookup’);
memberFunction = methodsNode.AOTfindChild( ‘lookup’ );
source =
@”public void lookup(FormControl _formControl, str _filterStr)
{
super(_formControl, _filterStr);
                         }” ;
        memberFunction.AOTsetSource(source, false);
memberFunction.AOTsave();
methodsNode.AOTsave();
tnAddr.AOTcompile();

    }

Dynalink in Dynamics AX 2009 Enterprise Portal


The classic Dynalink is still available when we are programming AX2009 Enterprise Portal.

So normally during the Enterprise portal programming, we don’t need to pass the parameter by using CreatingDataSetRun event to create the QueryBuildRange object and specify the range value (AX did that for us already!), if we have the table or EDT relations set up properly.

Apparently the context record is passed by the QueryString parameters.

For example, the QueryString “EPProjTableInfo.aspx?WTID=624&WKEY=%5b65534%3a5637144829%5d&WCMP=DAT”, AX will retrieve the context record by using the unique pair value (WTID = TableId, WKEY = RecId).

In the user control, we can use the following code to get the context record:

using Microsoft.Dynamics.Framework.Portal.UI;

using Microsoft.Dynamics.Framework.Metadata.Ax;

using Microsoft.Dynamics.Framework.Data.Ax;
AxTableContext context = AxBaseWebPart.GetWebpart(this).ExternalContext;

if (context != null &&

context.TableId == TableMetadata.TableNum(AxBaseWebPart.GetWebpart(this).Session, “ProjTable”))

{

string projId = context.DateKey.GetRecord(this.AxSession).GetField(“ProjId”).ToString()’;

}

In the DataSet, we can use args objects to return the context record as we do in AX client programming:

public void init()

{

TableId tableId;

ProjTable projTable;

ProjId projId;

super();

tableId = element.args().dataSet();

switch(tableId)

{

case tableNum(ProjTable):

projTable = element.args().record();

projId = projTable.projId;

break;

}

}

Add a field to InventJournalTrans, propagate to InventTrans


The link above does contain the solution — I have included the code from that page in case that page disappears or no longer becomes available. Thanks to gl00mie for answering on that site and providing this answer.
You should create a new InventMovement method like this:

public MyNewFieldType myNewField() { return MyNewFieldType::DefaultValue; // suppose your new field is an enum } 

Then modify \Classes\InventMovement\initInventTransFromBuffer

void initInventTransFromBuffer(InventTrans _inventTrans, InventMovement _movement_orig) { // ... append this line to the end of whatever else is already in this method _inventTrans.MyNewField = this.myNewField(); } 

And finally overload the new method in the InventMov_Journal class:

public MyNewFieldType myNewField() { return inventJournalTrans.MyNewField; } 

Transfer new fields from LedgerjournalTrans to LedgerTrans when posting


We added some new fields to both ledgerJournalTrans and LedgerTrans tables. I would like to copy those fields when posting, but i can’t seem to find where i can put the code. I don’t know where the data from LedgerJournaltrans is transferred to LedgerTrans.

Solved: this is done in LedgerVoucherTransObject class. I added parm methods for new fields and corrected newTransLedgerJournal method to include their transfer to LedgerTrans.

Create Payment Journal with X++


static server boolean processCheckPayment(CheckModule _checkModule)
{
LedgerJournalName ledgerJournalName;
LedgerJournalTable ledgerJournalTable;
LedgerJournalTrans ledgerJournalTrans;
LedgerJournalCheckPost ledgerJournalCheckPost;

Common common;
NumberSeq numberseq;
CustTrans custTrans;
CustTransOpen custTransOpen;
Specification specOffsetVoucher;

Parameters parameters = Parameters::find();
CustTable custTable = CustTable::find(_checkModule.CustAccount);
boolean result = false;
InvoiceId invoiceId;
;

while select custTransOpen
where custTransOpen.RefRecIdCheck == _checkModule.RecId &&
custTransOpen.UseRefRecId
{
custTrans = custTransOpen.custTrans();
invoiceId = custTrans.Invoice;

try
{
ttsbegin;

select firstonly ledgerJournalName
where ledgerJournalName.JournalName == parameters.LedgerJournalNameId &&
ledgerJournalName.JournalType == LedgerJournalType::CustPayment;

if(!ledgerJournalName.RecId)
throw error(“@CAM184”);

if(ledgerJournalName)
{
ledgerJournalTable.JournalName = ledgerJournalName.JournalName;
ledgerJournalTable.Name = ledgerJournalName.Name;
ledgerJournalTable.insert();

if(ledgerJournalTable)
{
numberseq = NumberSeq::NewGetVoucherFromCode(ledgerJournalName.VoucherSeries);
ledgerJournalTrans.JournalNum = ledgerJournalTable.JournalNum;
ledgerJournalTrans.Voucher = numberseq.voucher();
ledgerJournalTrans.TransDate = today();
ledgerJournalTrans.AccountType = LedgerJournalACType::Cust;
ledgerJournalTrans.Txt = CustTable::find(ledgerJournalTrans.AccountNum).Name;
ledgerJournalTrans.OffsetAccountType = ledgerJournalName.OffsetAccountType;
ledgerJournalTrans.OffsetAccount = ledgerJournalName.OffsetAccount;
ledgerJournalTrans.Dimension = ledgerJournalName.Dimension;
ledgerJournalTrans.CurrencyCode = ledgerJournalTable.CurrencyCode;
ledgerJournalTrans.ExchRate = ExchRates::find(ledgerJournalTable.CurrencyCode, datenull(), NoYes::No, NoYes::No).ExchRate;
ledgerJournalTrans.TransactionType = LedgerTransType::Payment;
ledgerJournalTrans.PaymMode = parameters.PaymMode;
ledgerJournalTrans.SettleVoucher = SettlementType::SelectedTransact;
ledgerJournalTrans.AccountNum = custTable.AccountNum;
ledgerJournalTrans.AmountCurCredit = custTransOpen.AmountCur;
ledgerJournalTrans.insert();

select custTransOpen
where custTransOpen.AccountNum == custTable.AccountNum &&
custTransOpen.RefRecId == CustTrans::findFromInvoice(invoiceId).RecId;

if(custTransOpen)
{
common = ledgerJournalTrans;
specOffsetVoucher = Specification_OffsetVoucher::newCommon(common, true);
if (!specOffsetVoucher.isMarked(custTransOpen.TableId, custTransOpen.RecId))
if (ledgerJournalTrans.RecId)
specOffsetVoucher.create(custTransOpen.TableId, custTransOpen.RecId, custTransOpen.AmountCur, ledgerJournalTable.CurrencyCode);
}

ledgerJournalCheckPost = LedgerJournalCheckPost::newLedgerJournalTable(ledgerJournalTable, NoYes::Yes);
ledgerJournalCheckPost.run();
result = true;
}
}
ttscommit;
}
catch
{
ttsabort;
result = false;
}
}
return result;
}

Invent Movement Journal Creation and Posting


static void MovementJournalImportExcel(Args _args)
{
 InventJournalTrans inventJournalTrans;
 InventDim inventDim;
 InventJournalTable inventJournalTable;
 InventJournalCheckPost journalCheckPost;
 InventJournalId journalId;
 journalTableData journalTabledata;
 InventBatch inventBatch;
 InventBatch localInventBatch;
 NumberSeq numberSeq;
 NumberSequenceReference numberSequenceReference;
 InventSerial inventSerial;
 InventSerial localinventSerial;
 int j,countno=0,i,k;
 real Scarp;
 FilenameOpen filename;

 Sysexcelapplication excelapp=sysexcelapplication::construct();
 sysexcelworksheet excelworksheet;
 sysexcelrange excelrange;
 sysexcelcells excelcells;
 // comvariant cellvalue=new comvariant();
 ;

 // Creating Journal Header
 inventJournaltable.initValue();
 inventJournalTable.JournalNameId = 'ERecover';
 numberSeq = new NumberSeq();
 numberSequenceReference = InventParameters::numRefInventJournalId();
 numberseq = NumberSeq::newGetNum(numberSequenceReference);

 inventJournalTable.JournalId = numberseq.num();
 inventJournalTable.Description = InventJournalName::find(inventJournalTable.JournalNameId).Description;
 inventJournalTable.insert();

 excelapp.workbooks().open('C:\xx.xls');
 excelworksheet=excelapp.worksheets().itemFromNum(1);
 excelcells=excelworksheet.cells();

 // Creating Unit Numbers
 for(i=301;i<=5600;i++)
 {
 inventBatch.clear();
 inventBatch.initValue();
 inventBatch.itemId = excelcells.item(i,11).value().bStr();
 inventBatch.inventBatchId = excelcells.item(i,1).value().bStr();
 localinventBatch = InventBatch::find(inventBatch.inventBatchId,inventBatch.itemId);

 if(!localinventBatch)
 {
 inventBatch.OakSerialUnit = excelcells.item(i,2).value().bStr();
 inventBatch.insert();
 }
 }

 //Creating Appartment Numbers
 for(k=1;k<=648;k++)
 {
 inventSerial.clear();
 inventSerial.initValue();
 inventSerial.InventSerialId = excelcells.item(k,8).value().bStr();
 inventSerial.ItemId = excelcells.item(k,11).value().bStr();
 localinventSerial = InventSerial::find(inventSerial.InventSerialId,inventSerial.ItemId);

 if(!localInventSerial)
 {
 inventSerial.ProdDate = systemDateGet();
 inventSerial.insert();
 }
 }

 // Creating Journal Lines
 for(j=301;j<=5600;j++)
 {
 inventJournalTrans.clear();
 inventJournalTrans.initValue();
 inventJournalTrans.TransDate = systemDateGet();
 inventJournalTrans.LedgerAccountIdOffset = "99999";
 inventJournalTrans.JournalType = InventJournalType::Movement;
 inventJournalTrans.JournalId = inventJournalTable.JournalId;
 numberSeq = new NumberSeq();
 numberSequenceReference = InventParameters::numRefInventJournalVoucherId();
 numberseq = NumberSeq::newGetNum(numberSequenceReference);

 inventJournalTrans.Voucher = numberseq.num();
 inventJournalTrans.ItemId = excelcells.item(j,11).value().bStr();
 // defaulting branch and item name
 inventJournalTrans.CostAmount = InventTable::find(inventJournalTrans.ItemId).inventTableModuleInvent().Price;
 inventJournalTable = InventJournalTable::find(inventJournalTrans.JournalId);
 inventDim.InventLocationId = excelcells.item(j,10).value().bStr();
 inventDim.inventBatchId = excelcells.item(j,1).value().bStr();
 inventDim.inventSerialId = excelcells.item(j,8).value().bStr();
 inventJournalTrans.InventDimId = inventDim::findOrCreate(inventDim).inventDimId;
 inventJournalTrans.Qty = 1;
 inventJournalTrans.AdjustmentNotes = "Initial Data Load";
 inventJournalTrans.LineNum = j;

 inventJournalTrans.insert();
 }

 excelapp.workbooks().item(1).saved(true);
 excelapp.workbooks().close();

 // Posting Journal
 journalTableData = JournalTableData::newTable(inventJournalTable);
 journalTableData.updateBlock(JournalBlockLevel::InUse,JournalBlockLevel::None);
 if (!infolog.num(Exception::Error))
 {
 infolog.clear(0);
 journalCheckPost =
 InventjournalCheckPost::newJournalCheckPost(JournalCheckPostType::Post,InventJournalTable);
 journalCheckPost.parmAutoBlock(true);
 journalCheckPost.run();
 }
 }

Smarter dialogs


I don’t know about you, but it seems to me that dialogs for jobs in AX gets more and more complicated. I have a feeling a few of them could solve most of the world’s problems with hunger and pollution, if I could only figure out how fill the dialog fields correctly…
Users need help and guidance with the dialogs and to give the best guidance you may need to react to the choices made by the user in the dialog.
Two methods on RunBase allow you to hook up some events from the dialog form with your RunBase inheriting class:

  • dialogSelectCtrl is executed every time a new control is selected. I.e. when you move from one field to another.
  • dialogTask is executed every time the task method of the dialog form is called.

Here’s an example of how you can enable or disable fields based on what the users selects.

class dialogTest extends RunBase
{
    DialogField     dialogFieldCustVend;
    DialogField     dialogFieldCustAccount;
    DialogField     dialogFieldVendAccount;
}
public container pack()
{
    return conNull();
}
public boolean unpack(container packedClass)
{
    return true;
}
static void main(args _args)
{
    dialogTest   dialogTest = new dialogTest();
    ;
dialogTest.prompt();
}
protected DialogRunBase dialog()
{
    DialogRunBase   dialog = super(dialog, true);
    ;
dialogFieldCustVend = dialog.addField(typeId(NoYesId), "Show vendor?");
dialogFieldCustAccount = dialog.addField(typeId(CustAccount));
dialogFieldVendAccount = dialog.addField(typeId(VendAccount));
// We start out by disabling the VendAccount field
dialogFieldVendAccount.fieldControl().enabled(false);
dialog.allowUpdateOnSelectCtrl(true);
return dialog;
}
public void dialogSelectCtrl()
{
   super();

   dialogFieldCustAccount.enabled(dialogFieldCustVend.value() == NoYes::No);
   dialogFieldVendAccount.enabled(dialogFieldCustVend.value() == NoYes::Yes);
}