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);
}

How to write code to create Item counting journal line in AX 2009


My task is created an item counting journal line through X++ code

InventDim inventDim;
InventJournalTrans journalTrans;
TmpImportInventJournal tableBuffer;
InventJournalTable inventJournal;
real lineNum = 1;
TmpImportInventJournal tmpTable; // tmpTable here is used to stored item counting data
InventJournalName inventJournalName;
NumberSeq numberSeq;
;
ttsbegin;

select forupdate * from inventJournal
where inventJournal.JournalId == inventJournalId;

select firstonly inventJournalName
where inventJournalName.JournalNameId == InventParameters::find().CountJournalNameId;
numberSeq = NumberSeq::newGetVoucherFromCode(inventJournalName.VoucherSeqId);

while select * from tmpTable
{
inventDim.clear();
journalTrans.clear();
inventDim.initValue();
inventDim.configId = tmpTable.configId;
inventDim.inventBatchId = tmpTable.inventBatchId;
inventDim.InventLocationId = tmpTable.InventLocationId;
inventDim.inventSerialId = tmpTable.inventSerialId;
inventDim.InventSiteId = tmpTable.InventSiteId;
inventDim.wMSLocationId = tmpTable.wMSLocationId;

inventDim = InventDim::findOrCreate(inventDim);

journalTrans.Voucher = numberSeq.voucher();
journalTrans.initValue();
journalTrans.initFromInventJournalTable(inventJournal);
journalTrans.LineNum = lineNum;
journalTrans.JournalType = inventJournal.JournalType;
journalTrans.TransDate = tmpTable.TransDate;

journalTrans.ItemId = tmpTable.ItemId;
journalTrans.initFromInventTable(InventTable::find(tmpTable.ItemId));

journalTrans.Counted = tmpTable.Counted;

Try replacing the statement journalTrans.Counted = tmpTable.Counted with:
//
journalTrans.Counted = tmpTable.Counted;
journalTrans.InventOnHand = InventSumDatePhysicalDim::onHandQty(countDate, itemId, inventDim,tmpInventDimParm);
//

journalTrans.InventDimId = inventDim.inventDimId;

journalTrans.validateWrite();
journalTrans.insert();
//
Also, replace the call to journalTrans.inser() with:
JournalTrans.insert(NoYes::Yes);
JournalTrans.inventMovement().journalSetCounted();
JournalTrans.update();
//

lineNum ++;
}

inventJournal.NumOfLines = lineNum -1;
inventJournal.update();

tmpTable.clear();
delete_from tmpTable;

ttscommit;

Edit method in axapta


Requirement:: We need to write the edit method on the places where we need to select the records and pass it to the business logic for further processing. Also, we need edit methods to display the values of the related record from other table when the related table is not a part of the form datasource. The same purpose can be handled using display method as well but edit method allows us to modify the values in the display method. So, we can say that:

Edit Method = Display Method + Editing capability
How to write an Edit Method: We can write an edit method using the code shown below. Before getting in to the code, we must understand the requirement of the below code:
· We have a form which is listing the Project Invoices in a grid
· We need to have a checkbox next to all the records to select/deselect the records
· We want to keep the Record Ids of the selected records in to a container so that we can use it for processing.
· When a record is checked, we must check in the container if the record already exists in the container or not. If it exist, we must return true so that the form show the value as checked.

Else, we can create or delete the entry in the container basis the user action like if user has checked the checkbox, we will make an entry in to the container or if user has unchecked the checkbox, we will delete the entry from the container

edit NoYes MarkSKUs(boolean set,
InventTable Invent,
NoYes _markSKUs)
{

if (set)
{
MarkMap.insert(Invent.RecId,_markSKUs);
MarkMap.valueSet();
}
else
{
if (MarkMap.exists(Invent.RecId))
{
_markSKUs = MarkMap.lookup(Invent.RecId);
}
}

return _MarkSKUs;
}

How to create return Order from code


static void SR_CreateReturnOrderAfterInvoice(Args _args)
{
CustInvoiceJour _invoiceRec;
str _returnReason;
CustInvoiceTrans custInvoiceTrans;
SalesLine salesLine;
SalesTable newRetOrder;
CustInvoiceJour custInvoiceJour;

SalesTable createReturnOrderHeader(CustInvoiceJour invoiceRec)
{

SalesTable old, newRec;
boolean bChecksOk = true;
;

old = SalesTable::find(invoiceRec.SalesId);
newRec.initReturnFromSalesTable(old);
newRec.CustAccount = old.CustAccount;

newRec.initFromCustTable();

newRec.CustInvoiceId = invoiceRec.InvoiceId;
newRec.ReturnDeadline = today();
newRec.ReturnReasonCodeId = ’21′; // Defective
newRec.SalesType = SalesType::ReturnItem;
newRec.SalesTaker = SysCompanyUserInfo::current().EmplId;

if ( newRec.ReturnReasonCodeId == ” && CustParameters::find().ReturnOrdersReasonReq ||
newRec.ReturnReasonCodeId != ” && !ReturnReasonCode::exist(newRec.ReturnReasonCodeId) )
{
checkFailed(strfmt(“@SYS26332″, fieldid2pname(tablenum(SalesTable), fieldnum(SalesTable, ReturnReasonCodeId))));
bChecksOk = false;
}

if ( bChecksOk && newRec.validateWrite())
{
newRec.insert();
}
else
{
throw error(“@SYS18722″);
}

return newRec;
}

ttsbegin;

// first we need to create the sales order header for the return order
select custInvoiceJour where custInvoiceJour.RefNum == RefNum::SalesOrder && custInvoiceJour.InvoiceId == ’101231′;

newRetOrder = createReturnOrderHeader(custInvoiceJour);

while select * from custInvoiceTrans where custInvoiceTrans.SalesId == custInvoiceJour.SalesId
&& custInvoiceTrans.InvoiceId == custInvoiceJour.InvoiceId
&& custInvoiceTrans.InvoiceDate == custInvoiceJour.InvoiceDate
&& custInvoiceTrans.numberSequenceGroup == custInvoiceJour.numberSequenceGroup
{
// now we need to populate all the necessary fields for the new salesline
// using the existing invoice and the new sales order
salesLine.initFromCustInvoiceTrans(custInvoiceTrans);
salesLine.initFromSalesTable(newRetOrder);

// udpate the quantity
salesLine.ExpectedRetQty = -custInvoiceTrans.Qty;

if (salesLine.ExpectedRetQty > 0)
{
error(“@SYS53512″);
ttsabort;
}

// set the quantity and amount fields
salesLine.LineAmount = salesLine.returnLineAmount();
salesLine.SalesQty = 0;
salesLine.InventTransIdReturn = custInvoiceTrans.InventTransId;

//create the line
salesLine.createLine(true, false, false, false, false, false, false, false, salesLine.InventTransId);

// clear the buffer
salesLine.clear();
}

ttscommit;

info(strfmt(‘Newly created return order is %1′, newRetOrder.SalesId));

}

Reading Data through SQL Data Reader in AX 2009


Reading Data through SQL Data Reader in AX 2009

static void CheckDatabaseConThroughDotNet(Args _args)
{
System.Data.SqlClient.SqlConnection con;
System.Data.SqlClient.SqlCommand com;
System.Data.SqlClient.SqlDataAdapter da;
System.Data.SqlClient.SqlDataReader dr;
System.Data.DataSet ds;
str _vendName;
;

try
{
con = new System.Data.SqlClient.SqlConnection(strfmt(“Data Source=Ibrahim; Initial Catalog=DynamicsAx; Integrated Security=true”));
com = new System.Data.SqlClient.SqlCommand(“Select * from VendTable”,con);

con.Open();
dr = com.ExecuteReader();

while(dr.Read())
{
// _vendName = dr(0);

}
con.Close();

}
Catch(Exception::Error)
{
info(“error in Error Class”);
}
Catch(Exception::CLRError)
{
info(CLRInterop::getLastException().ToString());
}
}

Posting a ledger journal


Here is the adapted example for posting a ledger journal line. Simply replace values between #s (#value#):

static void ExampleLedgerJournal(Args _args)
{
    LedgerJournalTable      ledgerJournalTable;
    LedgerJournalTrans      ledgerJournalTrans;
    LedgerJournalCheckPost  ledgerJournalCheckPost;
    NumberSeq               numberSeq;
    ;

    ttsbegin;

    // Journal name
    ledgerJournalTable.JournalName = "#JOURNALNAME#"; // ex. Daily, daytrans, etc.
    ledgerJournalTable.initFromLedgerJournalName();
    ledgerJournalTable.Name = "#DESCRIPTION#";  // description for this journal
    ledgerJournalTable.insert();

    // Voucher
    numberSeq = NumberSeq::newGetVoucherFromCode(LedgerJournalName::find(ledgerJournalTable.JournalName).VoucherSeries);
    ledgerJournalTrans.Voucher = numberSeq.voucher();

    // Lines
    ledgerJournalTrans.JournalNum = ledgerJournalTable.JournalNum;
    ledgerJournalTrans.CurrencyCode = CompanyInfo::standardCurrency();
    ledgerJournalTrans.ExchRate = Currency::exchRate(ledgerJournalTrans.CurrencyCode);
    ledgerJournalTrans.AccountNum = "#ACCOUNT#";
    ledgerJournalTrans.AccountType = LedgerJournalACType::Ledger;
    ledgerJournalTrans.AmountCurDebit = #VALUE#;
    ledgerJournalTrans.TransDate = systemDateGet(); //Avoid the Today function
    ledgerJournalTrans.OffsetAccount = "#OFFSET ACCOUNT#";
    ledgerJournalTrans.Txt = "#TXT#";
    ledgerJournalTrans.insert();

    //Posting the Journal
    ledgerJournalCheckPost = LedgerJournalCheckPost::newLedgerJournalTable(ledgerJournalTable, NoYes::Yes);
    ledgerJournalCheckPost.run();

    ttscommit;
}

Dynamics AX EP timeout issue


Sometime for debugging or traversing large data in EP causing an issue of timeout, we can increase the timeout by setting the AsyncPostBackTimeout for AJAX which was causing the timeout. Here is the code which we can write in Page_Load event:

protected void Page_Load(object sender, EventArgs e)
{
ScriptManager scripts = ScriptManager.GetCurrent(this.Page);

if (scripts != null)
{
scripts.AsyncPostBackTimeout = 800; // 800 seconds
}
}

Dynamics Ax 2009 – Enterprise portal – Page deployment


A page in Enterprise portal is defined by 2 objects in Ax 2009

1. Web menu item URL

Path AOT –> Web –> Web Menu Items –> URLs

2 Page definitionPath AOT –> Web –> Static Files –> Page definitions

Every time a Page is changed (added / removed user controls / web parts) the page definition needs to be updated.

To do this locate the URL of the web page in the AOT

and right click –> Import

After importing the file, look at the page definition for the corresponding URL. It will not have an object in the current working Layer.

Deploying specific EP pages:

Right click on the page definition –> deploy page

This deploys the page and a message is shown