Thursday, August 27, 2009

RunOn property in Axapta

The class has a RunOn property that have three values: Client, Called From and Server. Objects created from the class will then live at the location specified.
If you choose Called from, the object will live at the tier where the code creating it (by calling the new constructor) is running.
Classes extending other classes will also inherit the RunOn property. You cannot change it if it is Client or Server. If it is Called from, you can leave it or change it to Client or Server.
But someone may wonder that menu items have their RunOn properties, what will happen if the RunOn property of a given menu item pointing to a class is set to Server, whereas the class's RunOn property is set to Client. The answer is that only if the Class's RunOn property is set to Called From, the objects will be created determined by menu item's RunOn property.
Also there is another situation, the class has static main method which has a RunOn property as well. What will happen if the menu item's RunOn property is set to client, whereas main method has a server modifier. The answer is it will determined by main method's modifier.
Axapta will create the objects according to the prioritized sequence of Class's RunOn property, Class's main method's modifier, menu item's RunOn property. And please notice that in Fat Client mode, even you can set the Class's RunOn property to Server, Axapta will still create the objects in client side instead of Server side.

Wednesday, August 5, 2009

Create and Post Free Text Invoice in AX

Here is a sample class which is called via Dialog framework to create & post free text invoice using X++ code.

Job:
public void freeTextInvoicePostTestJob()
{
Dialog dialog;
DialogField dlgCustAcc;
DialogGroup dialogPeriodLengthGroup, dialogPeriodLengthGroup1;
DialogField dlgLedgerAcc;

dialog = new Dialog("Free-Text Invoice");
dialogPeriodLengthGroup1 = dialog.addGroup('Cust Table');
dlgCustAcc = dialog.addField(extendedTypeStr(CustAccount));
dialogPeriodLengthGroup = dialog.addGroup('Ledger Table');
dlgLedgerAcc = dialog.addField(extendedTypeStr(LedgerAccount));


if(dialog.run())
{
if(dlgCustAcc.value() && dlgLedgerAcc.value() != '')
FreeTxtInvoiceCreatePost::main(dlgCustAcc.value(), dlgLedgerAcc.value());
else
throw error(strfmt("Either CustAccount or LedgerAccount info is missing."));
}
}

class FreeTxtInvoiceCreatePost
{
}
static void main(CustAccount _custAccount, LedgerAccount _ledgerAccount)
{
CustInvoiceTable custInvoiceTable;
CustInvoiceLine custInvoiceLine;
CustTable custTable;
LedgerTable ledgerTable;
CustPostInvoice custPostInvoice;
LineNum lineNum;
int i;

ttsbegin;
custTable = CustTable::find(_custAccount);
custInvoiceTable.initFromCustTable(custTable);
custInvoiceTable.insert();
ttscommit;

for(i=1; i<=100; i++)
{
ttsbegin;
ledgerTable = LedgerTable::find(_ledgerAccount);
custInvoiceLine.clear();
custInvoiceLine.initValue();
custInvoiceLine.LedgerAccount = ledgerTable.AccountNum;
custInvoiceLine.initFromCustInvoiceTable(custInvoiceTable);
custInvoiceLine.AmountCur = 10.00;
custInvoiceLine.Description = 'FreeTxIv' + int2str(i);
custInvoiceLine.TaxItemGroup = 'full';
custInvoiceLine.ParentRecId = custInvoiceTable.RecId;

lineNum += 1;
custInvoiceLine.LineNum = lineNum;
custInvoiceLine.insert();
ttscommit;
}

custPostInvoice = new CustPostInvoice(custInvoiceTable);
custPostInvoice.run();
}

Updating records and calling super

Before a record in AX gets updated an external application gets started. This external application is able to do additional update on the same record in AX by using AIF. As the performance of the external route is slow, an additional check is needed to start this process only if needed.

So what do we have?

A. Do I need to compare this with this.orig() before or after super?
B. Do I need to call this external application before or after super?

If we call the external application before super, AX will complain that another user has updated the record. So we have to do it after super. Fine, but what happens…. After super the original record gets equal to the current record. Ouch so the difference between the record and the original record only exists before super. The solution is to make a local buffer variable in the update method that references the original record before calling super. This buffer will still be used after calling super.

Example:

void update()
{
CustTable ctBuffer = this.orig();
Super();
If(this.name != ctBuffer.name)
//call external application
}

Monday, August 3, 2009

Where do you want your code to run today

Much of the X++ code you write can run on either the Application Object Server, or the Client. The client can be the Win32 client, or BC.NET for Enterprise Portal. MorhpX generally will not direct your code to run on a specific tier, but you as an application developer can control it.

Whether code runs on the server or on the client has performance and security implications, and should be given careful consideration as a part of design. Occasionally it will be correct to methods run on either tier, but usually this is not the case.

As MS move forward implementing tasks in upcoming release, developers will identify which resources to grant access to for a given task. These resources include tables/fields and server entry points. A server entry point is a specially decorated method that runs on the server. Tables/fields accessed inside this server entry point need NOT be identified with the task, greatly reducing the complexity and effort required to implement the task. If the server entry point is NOT executed on the server, then table/field access is still validated, and will fail if the code accesses a table/field that is not included with the task.

So, in short:
Set the RunOn AOT property to Server or Client for new classes, unless you have a reason to leave the default
Include considerations about where the code runs in your design, and look for it when reviewing design documents
Declare static class methods, table static and instance methods with either the "server" or the "client" keyword, unless you have a reason not to
Look for ways to limit direct table and field access in form methods, try to move this into a class

This page MSDN describes where methods run:
http://msdn.microsoft.com/en-us/library/aa891949.aspx. Additional information to cover more object types at http://msdn.microsoft.com/en-us/library/aa634829.aspx.

Tuesday, July 21, 2009

Iterate all records from grid

To iterate all record from a grid is accomplished by :

VendOutPaymForParams_FI exportSetupLocal;

for (exportSetupLocal = exportSetup_ds.getNext();exportSetupLocal;exportSetupLocal=exportSetup_ds.getNext())
{
B....
}

Tuesday, July 14, 2009

Getting rid of the "Loss of precision" warning message

A question came up at today's webinar where a developer had a (presumably legitimate) reason to cast a real value into an integer value. The X++ language does not allow explicit casting (there's no support for it in the language), but the compiler will do its best to satisfy the user and do the conversion on its own. In this case, however, it issues a warning message, lest this is not what the user wanted.

One solution is to use the anytype type to hold the vaue for conversion and then using the any2int function, as shown below:

static void Job47(Args _args)
{
real r = 3.13;
int i = r; // Warning is issued here
anytype a;

a = r; // Assign to an anytype variable...
i = any2int(a); // ... and back into an int

print r;
print i;
pause;
}
This should be packaged into a function, maybe called int RealToInt(real arg).

Another way would be doing the conversion in managed code (through the System.Convert::ToInt32(object) method), but the performance will not be as good because of the marshalling that needs to take place.

Forthcoming changes to the X++ language

Very informative link for new X++ release
http://blogs.msdn.com/x/archive/2009/06/29/forthcoming-changes-to-the-x-language.aspx

Monday, July 6, 2009

How to get all changes done in usr layer into project.

Create a new project and open the project.

Press Ctrl+f3 or click on the icon advance filter/sort on the toolbar of the
project, a dialog with name project filter will be opened.

In project filter, select append and aot.Click select for the query dialog
to open enter the query layer usr in the utillevel range and click Ok to
close query dialog .
Click Ok to close the project filter dialog. This will create a project with the objects of usr layer.

Friday, July 3, 2009

Physics behind the data source refresh(), reread() and research() method

.refresh() will not reread the record from the database. It basically
just refreshes the screen with whatever is stored in the form cache.

.reread() will only re-read the CURRENT record from the DB so you
should not use it to refresh the form data if you have added/removed
records. It's often used if you change some values in the current
record in some code, and commit them to the database using .update()
on the table, instead of through the form datasource. In this case
.reread() will make those changes appear on the form.

.research() is probably what you want. This will rerun the existing
form query against the datasource, therefore updating the list with
new/removed records as well as updating existing ones. This will
honour any existing filters and sorting on the form.

.executeQuery() is another useful one. It should be used if you have
modified the query in your code and need to refresh the form. It's
like .research() except it takes query changes into account.

In general, you only need to use one of these in any specific
circumstance.

Set the specific row in a grid

The specific row of grid can be set by calling the dataSource_ds.findRecord(Common _buffer) method. Suppose we want to select third row (i.e Account # 4003) in a customer table grid, here is the code

CustTable_ds.findRecord(CustTable::find('4003'));

Tuesday, June 9, 2009

Trade & Logistics

Some T & L notes :


The Purchase order form opens, by default in the Simple view and shows the last purchase order created.
Unit - The purchase unit is the unit of measure that the item is purchased. There is a close relationship between the purchase unit and the inventory unit. For example, the item may be purchased in kilos and stocked in grams.
One-time supplier - For use of a supplier that is not already in the Vendors form.
Invoice account - Invoice account is used if the account number of the vendor you send the invoice to and pay differs from the vendor with whom you place the purchase order.
RMA number - The dialog box displays the Return Merchandise Authorization number (RMA number) when Return Item is selected in the Purchase type field. This number is provided by your supplier and is used for tracking a return item. The field is mandatory when the purchase type is Returned item.
In this field group, specify the language setting for the purchase order. This affects the language that is used for item names and for printing external purchase order documents.
EXAMPLE: Select an item and click Setup - Language - Item
description. Select a language and enter the translation text. Create a new
purchase order and in the Language field group select the language for which
you created a translated text. Print, for example, a receipts list and the
item's name is printed out using the foreign language text.

Trade & Logistics Puchase Order Types

Types of Purchase Order -

There are 6 Purchase order types:
Journal
Quotation
Subscription
Purchase Order
Returned Item
Blanket Order

Journal
The first Purchase order type is the journal. This type is used as a draft. It does not affect stock quantities and does not generate any item transactions and the quantity on the order line will not be considered in the Master scheduler. It can't be posted
EXAMPLE: A purchase order of the type Journal can be used when importing data by batch; in this manner, the purchase order can be reviewed and evaluated without affecting inventory, on-order, or other numbers.

Quotation
This kind of purchase order is used if the vendor has not yet committed to fulfilling the order if the company has not confirmed the purchase order. Quotation type generates an issue lot with the type Quotation in the inventory and optionally in the Master scheduler.
Unlike the Journal type, the Quotation makes an entry in the inventory transaction table. Making this transaction is what enables Microsoft Dynamics AX to use this information for Master scheduling purposes.

Subscription
This kind of purchase order is used for repeated purchases of the same goods or services. When a packing slip is updated, Microsoft Dynamics AX generates a receipt. When the invoice is updated for the receipt, a new packing slip or invoice entry can be updated for the same purchase line immediately or at some future date. The order will never be at an Invoiced status only Open or Received.

Returned Item
This type is used when you return goods to the vendor. A Return Merchandise Authorization (RMA) number supplied by the vendor is required when entering this kind of order

Blanket Order
This kind of purchase order is used if there is a contract with the vendor and you want to order from the contract. Typically, a company uses blanket orders to receive better pricing conditions as the blanket order quantity is bigger than on single purchase orders. You can create a Release order to release, order, and invoice items until the contract is fulfilled. Blanket orders do not affect stock quantities, do not generate item transactions, and are not included in Master scheduling. Release orders, issued from Blanket orders, do affect all the above.

Trade and Logistics - Sales order Types

There are 6 types of Sales orders -

Journal
Subscription
Sales Order
Returned item
Blanket order
Item Requirements

Journal
Sales orders of the type Journal resembles purchase orders of type Journal because they are also used as types of draft sales orders.Journals help when bringing data into the system that may not meet quality or other standards, as can be the case with data loads or data keyed by a new or temporary worker.A sales order of the type Journal does not affect stock quantities and does not generate item transactions nor will the quantity on the order line be considered in the Master scheduler.

Subscription
This kind of sales order is used for repeated sales of the same goods or services to the same customer. When a packing slip is updated, Microsoft Dynamics AX generates a packing slip. When the invoice is updated, a new packing slip or invoice entry can be updated for the same sales line. The order never has an Invoiced status, only Open or Delivered.

Sales Order
This kind of sales order is used when the customer confirms that they want the order. When you create a new order, the type can be set to default to Sales order type in the parameters form depending on the client's business process.

Returned Item
This kind of sales order is used when receiving goods back from a customer. A Return Item Number is required for this kind of order and can automatically be assigned by Microsoft Dynamics AX 4.0 by the number sequence set up or manually assigned by the user.

Item Requirements
The Sales order type of Item Requirements is connected to the Microsoft Dynamics AX Project Module. When you create your item requirements in the Project module, you create a sales order of the type Item requirements.

BOM overview and Types

BOM

BOM is one of the most important documents in a manufacturing company. Like the
recipe for a cake, it is a comprehensive list of all the ingredients required to
make or assemble a finished item. These ingredients are the components, parts
and raw materials that are used.

BOM Types
Item - usually is purchased from outside source
BOM - produced in-house and contains components to go for the finished product
Service - represents a service e.g. hourly rates for services during manufacturing

Ten MorphX Tricks

Here's a great video from mfp...
http://channel9.msdn.com/posts/mfp/10-MorphX-tricks-in-10-minutes/

Wednesday, May 27, 2009

WMS in Microsoft Dynamics® AX 2009. Shipping Process Overview

ntroduction The WMS (Warehouse Managements System) encompasses the core components within average Microsoft Dynamics AX installations that are implemented to manage and run world class warehouses. The WMS functionality is enabled by the configuration Read More...

Changes in Sales and Transfer Order Picking from Microsoft Dynamics AX 4.0 to Dynamics AX 2009

Overview The purpose of this post is to present the major changes and new functionality that was introduced for sales and transfer order picking in AX 2009. The aim and the idea behind these changes is to move towards a single system for picking that Read More...

Supply Chain Management in Dynamics AX

Here is a link of SCM in Dynamics AX.

Dynamics Ax 2009 VPC available

Microsoft have released a Virtual PC image of Dynamics Ax 2009 (the new name for Dynamics Ax version 5)

You can download it and user manuals from here (requires partnersource access)

It's almost 7 GB in total and is designed to work on a single laptop/PC (as opposed to a server)

Dynamics Ax - Task Recorder

This is a free add-on for Ax that allows you to record whatever you're doing in Ax (forms that open, user input and screenshots) and automatically create documentation for you

So far I've been using it to produce Microsoft Word documents that will become part of a user manual for a bespoke Ax module

This is the first time we've actually managed to get it to work! Whenever we've tried it in the past it just wasn't useable
So for anyone else who's had problems with it, try the latest version, after having used it for several weeks without problems, I can recommend it

It's a LOT easier than taking hundreds of screenshots and cutting/pasting them into a word document

It's by no means perfect though, and there is still a fair amount of editing required before the document that it spews out is presentable enough to be of any use to an end-user, but it does make life easier

You can download it from here (requires partnersource login)

There's a brief but succinct description here at the axaptapedia too

Friday, April 24, 2009

How to traverse multiple selected lines in a grid control by using X++ code in Microsoft Axapta

This post describes how to use X++ code to traverse multiple selected lines in a grid control in Microsoft Business Solutions - Axapta. Do this when multiple rows of the information in the grid control contain the information which is required to perform the required request.
For example, you can use the following code in the click event of the button if you want to traverse two selected lines when the second row and the fourth row are highlighted in a grid control.

void clicked()
{
CustTable ct;
;
//ct is set to the forms data source and using a cursor goes through each record selected in the grid.
for (ct = DataSource1_ds.getFirst(true) ? DataSource1_ds.getFirst(true): DataSource1_ds.cursor(); ct;ct=DataSource1_ds.getNext())
{
print ct.AccountNum," ",ct.Name;
}
super();
}

Sample X++ code that you can use to disable or to hide a query range in Microsoft Axapta

The following code sample shows how to use X++ code to create a query that contains three ranges. In the code sample, only one specified range can be changed by the end user. In the code sample, the following conditions are true:
• The first range is not shown.
• The second range is shown but cannot be edited.
• The third range can obtain the input from the end user.

static void QueryStatusTest(Args _args)
{
Query q;
Queryrun qr;
QueryBuildRange qbr,qbr1,qbr2;
QueryBuildDataSource qbds;
VendTable vt;
;

// Create an instance of the query class and then provide a name of "Vendors."
q = new query("Vendors");

// Create a data source that connects to the VendTable table.
qbds = q.addDataSource(tablenum(VendTable));

// Use three different field names to create three ranges.
qbr = qbds.addRange(fieldnum(VendTable,AccountNum));
qbr1 = qbds.addRange(fieldnum(VendTable,Blocked));
qbr2 = qbds.addRange(fieldnum(VendTable,Name));

// Set the values for the three ranges.
qbr.value('3*');
qbr1.value(strfmt('(%1 == %2)',fieldstr(VendTable,Blocked),any2int(CustVendorBlocked::No)));
qbr2.value('Office World');

// Set the status of each range.
qbr.status(1);
qbr1.status(2);
qbr2.status(0);

// Create an instance of the QueryRun class.
qr = new QueryRun(q);

// Verify that the QueryRun form is active, and then parse the tablenum value through the VendTable table.
If (qr.prompt())
{
while (qr.next())
{
vt = qr.get(tablenum(VendTable));
print vt;
}
pause;
}

// Show the SQL statement that is produced by the query.
info (qr.query().dataSourceNo(1).toString());

}
Note: The status method provides the function for each range.