Create Return Order in Dynamics AX using X++

A customer may return an item to a company for various reasons. For example, it may be defect or not fulfill the customer’s expectations.
The return process begins when you receive a request from a customer to return an item and create a Return order in Microsoft Dynamics AX 2009.

Below code will help you to create a return order of already invoiced Sales order.
Note: This code will return all the items by looping through the CustInvoiceTrans. However, code can be tweaked as per your requirement and can select only a particular line and specific qty [custInvoiceTrans.Qty].

Return orders are avaialble from AR>> Common Forms >> Return order details


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

}

Advertisements

Easy way to write queries/select statements – Editor scripts

Editor scripts help us to perform frequent tasks more quickly in the X++ code editor. For example, there are scripts to create templates for certain types of code constructs and methods, to convert lines of code into comments.

This post will help the developers to quickly write the joins based on the relations between table. Tired of writing code or new to Joins, please follow the code below

To use a script:

Place your cursor in the code editor window, and then press Alt+M.

Press Alt+M, and then Queries > InnerJoin. [Note : In this post , I have added only 4 joins, Many more to come]

Overview :

Select the inner join or any join as per your need.

Once you select InnerJoin from the editorscripts, a dialog will be opened and will request you add the master and childTable. For example , provide SalesTable and salesLine as shown below

Click on Ok button in the dialog
Below is the output.. Isn’t easy ??? 🙂

Well, now lets look at the code. Add the below five methods to your “EditorScripts” class. This class is available in your AOT >> Classes >> EditorScripts


Method1
_______
public void Queries_ExistsJoin(Editor e)
{
Dialog dialog = new Dialog(“Query helper”);
DialogField dfMasterField, dfChilField;
;

dfMasterField = dialog.addField(Types::String, “Parent table”);
dfChilField = dialog.addField(Types::String, “Child table”);

if (dialog.run())
{
e.insertLines(EditorScripts::buildQueryStatement(‘exists join’, dfMasterField.value(), dfChilField.value()));
}
}

Method2
_______
public void Queries_InnerJoin(Editor e)
{
Dialog dialog = new Dialog(“Query helper”);
DialogField dfMasterField, dfChilField;
;

dfMasterField = dialog.addField(Types::String, “Parent table”);
dfChilField = dialog.addField(Types::String, “Child table”);

if (dialog.run())
{

e.insertLines(EditorScripts::buildQueryStatement(‘join’, dfMasterField.value(), dfChilField.value()));
}
}

Method3
_______
public void Queries_NonExistsJoin(Editor e)
{
Dialog dialog = new Dialog(“Query helper”);
DialogField dfMasterField, dfChilField;
;

dfMasterField = dialog.addField(Types::String, “Parent table”);
dfChilField = dialog.addField(Types::String, “Child table”);

if (dialog.run())
{

e.insertLines(EditorScripts::buildQueryStatement(‘notexists join’, dfMasterField.value(), dfChilField.value()));
}
}

Method4
_______
public void Queries_OuterJoin(Editor e)
{
Dialog dialog = new Dialog(“Query helper”);
DialogField dfMasterField, dfChilField;
;

dfMasterField = dialog.addField(Types::String, “Parent table”);
dfChilField = dialog.addField(Types::String, “Child table”);

if (dialog.run())
{

e.insertLines(EditorScripts::buildQueryStatement(‘outer join’, dfMasterField.value(), dfChilField.value()));
}
}

Method5
_______

static str buildQueryStatement(str _joinType, TableName _masterTable, TableName _childTable)
{
DictRelation dictRelation;
Counter i;
str selectStatement;
DictField CMainDictField,CLineDictField;
str 1 firstAlphabet;
sqlDictionary s1, s2;

;

select * from s1 where s1.TabId == TableName2id(_masterTable);
select * from s2 where s2.TabId == TableName2id(_childTable);

if ((!s1) || (!s2))
{
throw error (“Table names are invalid.”);
}

if (_masterTable == _childTable)
{
throw error (“Master and child tables cannot be identical”);
}

firstAlphabet = strlwr(substr(_masterTable, 1,1));
_masterTable = strdel(_masterTable,1,1);
_masterTable = firstAlphabet + _masterTable;

firstAlphabet = ”;

firstAlphabet = strlwr(substr(_childTable, 1,1));
_childTable = strdel(_childTable,1,1);
_childTable = firstAlphabet + _childTable;

dictRelation = new DictRelation(tablename2id(_childTable));

dictRelation.loadTableRelation(tablename2id(_masterTable));

if (dictRelation.lines())
{
selectStatement += ‘ ‘+ str2capital(_masterTable) + ‘ ‘ + _masterTable +’; \n’;
selectStatement += ‘ ‘+ str2capital(_childTable) + ‘ ‘ + _childTable + ‘; \n’;

selectStatement += ‘ ;\n’;
selectStatement += ‘ while select * from ‘ + _masterTable + ‘ ‘+_joinType +’ ‘+ _childTable + ‘ where ‘;
for (i = 1; i <= dictRelation.lines(); i++)
{
CMainDictField = new DictField(tablename2id(_masterTable), dictRelation.lineExternTableValue(i));
CLineDictField = new DictField(tablename2id(_childTable), dictRelation.lineTableValue(i));
selectStatement += _masterTable + ‘.’ + CMainDictField.name() + ‘ == ‘ + _childTable +’.’+ CLineDictField.name() + ‘\n && ‘;
}
}
else
throw error(strfmt("@SYS59540",_masterTable, (_childTable)));

selectstatement = strdel(selectstatement, strlen(selectStatement), -3 )+'\n';
selectstatement += ' {\n';
selectstatement += @' //' + 'TODO::Business logic goes here\n';
selectstatement += ' }';

return selectstatement;
}

Happy Dax’ng 🙂

Expression Builder Lookup using X++

I was just wondering if there is any way of popping a lookup form during the program execution.

We have seen many ways of creating lookups – EDT’s, relations, AutoLookup and through custom code [SysTableLookup]

Let us consider an example: I have a select query whose behaviour should be dynamic based on the User input. We might have used query Framework classes many a times to do this.

I was just going through the standard classes and found this code useful with minimum tweaking of code.

Try out the below example: This example will help you to select the custAccount and based on the selected customer account it brings you the last invoiced sales order.

Note: The columns in the form are built runtime using the AutoLookup fields.

static void SR_expressionBuilderLookUp(Args _args)
{
CustTable custTable;
ExtendedDataTypeName extendedDataType = extendedtypestr(custAccount);
CustAccount custAccount;

Object expressionBuilderLookup;
Args args = new Args(formstr(SysExpressionBuilderLookup));
;

expressionBuilderLookup = new FormRun(args);
expressionBuilderLookup.parmExtendedDataType(extendedDataType);

expressionBuilderLookup.init();
expressionBuilderLookup.run();
expressionBuilderLookup.wait();

custAccount = expressionBuilderLookup.parmSelectedValue();

if(custAccount)
{
info(strfmt(‘Last SO of customer %1 is %2’, custAccount, CustTable::find(custAccount).lastInvoice().SalesId));
}
}

Below is the lookup image for your reference

Credit Note [Dynamics AX] using X++

This post will help to create credit note for a sales order based on the invent lot id. All the invoices raised for a particular sales line – Lot Id will be raised back as a credit note.

Information on Credit Note:

A credit note or credit memorandum (memo) is a commercial document issued by a seller to a buyer. The seller usually issues a Credit Memo for the same or lower amount than the invoice, and then repays the money to the buyer or sets it off against a balance due from other transactions

Below Code will help to create credit note for all the invoices raised against the sales line -lot id.

Please note: This code can be customized as per your requirements. This is just a template to help creating credit note using X++ code. Please test the code before use.

static void SR_CreateCreditNote_Sales(Args _args)
{
// Coded by Sreenath Reddy
CustInvoiceTrans custInvoiceTrans;
Dialog dialog = new Dialog(“Create credit note – for sales.”);
DialogField dfInventTransId;
SalesCopying salesCopying;
TmpFrmVirtual tmpFrmVirtualHeader;
TmpFrmVirtual tmpFrmVirtualLines;
boolean isCreditNoteCreated;
SalesId salesId;
SysInfoAction_FormRun SysInfoAction;

void loadTmpVirtualTableAndCreateCN(CustInvoiceTrans _custInvoiceTrans)
{
tmpFrmVirtualLines.TableNum = _custInvoiceTrans.TableId;
tmpFrmVirtualLines.RecordNo = _custInvoiceTrans.RecId;
tmpFrmVirtualLines.Id = _custInvoiceTrans.SalesId;
tmpFrmVirtualLines.LineNum = _custInvoiceTrans.LineNum;
tmpFrmVirtualLines.TransDate = _custInvoiceTrans.InvoiceDate;
tmpFrmVirtualLines.Qty = _custInvoiceTrans.Qty;

tmpFrmVirtualLines.write();

salesCopying = SalesCopying::construct(SalesPurchCopy::CreditNoteLines);
salesCopying.initParameters(salesTable::find(_custInvoiceTrans.SalesId, true),
tmpFrmVirtualLines,
tmpFrmVirtualHeader,
1,
true,
false,
true,
true,
false);

salesCopying.copy();
}
;

dfInventTransId = dialog.addField(typeid(InventTransId), “Lot id”, “Inventory transaction identifier/Lot id”);

dialog.addText(“This snippet will help to create credit notes for all the invoices raised for the lot id of salesLine”);

if (dialog.run())
{
salesId = CustInvoiceTrans::findInventTransid(dfInventTransId.value()).SalesId;
if (!salesId)
{
throw error (“Select only sales order – reference type.”);
}
while select custInvoiceTrans where custInvoiceTrans.InventTransId == dfInventTransId.value()
{
// Load the custinvoiceTrans details in to tmpFrmVirtualLines buffer
isCreditNoteCreated = true;
loadTmpVirtualTableAndCreateCN(custInvoiceTrans);
}
}

if (isCreditNoteCreated)
{
sysInfoAction = SysInfoAction_FormRun::newFormnameDesc(formstr(SalesTable), “show credit note”);
sysInfoAction.parmCallerBuffer(SalesTable::find(salesId));
info(strfmt(“Credit notes created succesfully for the SalesOrder %1 and for lotId %2″, salesId, dfInventTransId.value()),”,sysInfoAction);
}

}>

List view in Dynamics AX

In this post, I would like to help the developers who are new to Dynamics AX and how to work with list views and manipulate data using the listViews.

Follow the below steps to learn ListView control on the forms.

Step 1: Create a new form from AOT >> Forms >> Right click and name it as Example_ListView

Expand the newly created form and go to the Designs Node. Add a new Control called ListView and name it as “LeftListView” as shown below.

By default -AutoDeclaration property of the ListView will be “Yes”.

Now lets learn some important properties of the listView. Right click on the newly created ListView and go to its Properties [Use Alt + Enter shortcut key] . Change the View type property from “Icon” to “Report” s shown below.

Save the form and now let’s add coulmns to the list view. Since we have set the autodeclaration property of the LeftListView to “yes”, we can use this control inside the code.

Step 2: Override the init() method of the Example_ListView form and add the below lines of code to add columns to the list View as shown below

LeftListView.addColumn(1,new FormListColumn(‘List of customes’,1, 200));
Refer to the image below for the same.

Step 3: Now let us insert items to the list.
Override the run() method of the form and insert the below lines of code. We are actually fetching all the customer names from the standard CustTable and adding the same to the list.

public void run()
{
CustTable custTable;
;
super();

// Adding items to the list
while select Name from custTable
{
LeftListView.add(custTable.Name);
}

}
Below image is the same for the reference

Now let’s see how the items looks like in our list.
Open the Example_ListView form by using shortcut key “Ctrl + O ”
Below image is for your reference.

Step 4: Add a new button to the form by Right clicking the design >> Chose Button control. Name the button as SelectBtn and Text property set to “Get selected item” as shown below

Override the clicked() method of the nelwy created button and add the below lines of code. This code will help you to show the selected item by the user in the list upon clicking on the button in the infolog

void clicked()
{
FormListItem item;
int i;
;

super();

i = LeftListView.getNextItem(FormListNext::Selected);
while (i != -1)
{
item = LeftListView.getItem(i);
info (item.text());
i = LeftListView.getNextItem(FormListNext::Selected,i);
}
}

Below is the image for the reference

Note: By default the Listview will not allow the multiple selection of items on the list. To allow users multiple selection, go to the LeftListView control properties and change the property of MultipleSelection from “No” to “Yes” as shown below

Step 5: Select multiple items in the list[By using shift key] and click on the button to view the selected items by the user in the infolog. Below is the result.

Step 6: Move up and down the items [Arrange] in the list View. To do this add 2 new buttons to the Form. Name them as UpBtn and DownBtn . Provide the text property on the buttons as “Up” and “Down”

On the upBtn >> Overide the Clicked method and paste the below lines of code to move the item up [Select the item in the listview and use Up arrow to move the item upwards]

void clicked()
{
int i = LeftListView.getNextItem(FormListNext::Selected);

LeftListView.moveItem(i, i-1);
}

Similarly on the DownBtn >> Override the clicked method and paste the below code


void clicked()
{
int i = LeftListView.getNextItem(FormListNext::Selected);

LeftListView.moveItem(i, i+1);
}

Moveitem is the method which will help to move or arrange the items in the list through index. If we decrement the index, the item will be moved up and on incrementing the item will move down.

Step 6: Finally, how to move items from one list to another. To do this let’s create one more list in the form by right clicking the desgins and add new ListViewControl . Name the newly created ListView control to “BottomListView” and change the ViewType property of the listView to Report. [Refer to Step 1]

Below is the screen shot for your reference [Ignore the alignment, Beautification of the form is left to you :)]

Step 7: Now we need to add columns to this newly created list which we did in the Step 2.

Modify the init() method of the form to add the columns to the BottonListView

BottomListView.addColumn(1,new FormListColumn(‘Moved customers’,1, 200));

Below is the screenshot of init method for your reference

Step 8: Lets add one more button which should help to move item from the LeftListView to ButtonListView.
Create a new button and name it as “MoveBtn” and give the text property as “Move Items” as shown below.

Step 9: Override the clicked() method of the MoveBtn and add the below lines of code to move the items from one list to another.
Business logic : Get the selected item from the LeftlistView. Add to the another list i.e BottomListView. Delete the item/items from the LeftListView.

void clicked()
{
FormListItem item;
int i;
;

super();

i = LeftListView.getNextItem(FormListNext::Selected);

while (i != -1)
{
item = LeftListView.getItem(i);

BottomListView.addItem(item); //Add items to the BottomListView
LeftListView.delete(i); // Delete the selected item from the LeftListView

i = LeftListView.getNextItem(FormListNext::Selected,i);
}
}