Monday, March 16, 2009

Customized Comment In Your Code Editor

Standard code editor allows to create your own kind of comments. Generally, a style of comments depends on your programming style and the company's policies on that.

I prefer to frame changes I make in a code with parentheses in the following style:




// Voytsekhovskiy, Alexey (My company name) (2009/03/16) (#)
//-->
the code as it wasd before my changes
//<--


In order to have such an option in the editor's context menu I changed EditorScripts class as follows:

1. Created a new add-on function

boolean isEmptySelection(str s)
{
;
// delete all special symbols
return strLen(strRem(strRem(strRem(s," "),"\n"),"\r"))>0;
}


2. Changed getSelectedText standard method

// added here the new parameter takeAllIfEmpty
static str getSelectedText(Editor e, boolean takeAllIfEmpty = true)
{
int i;
str text;
str line;
int startLine = e.selectionStartLine()+1;
int endLine = e.selectionEndLine()+1;
int startCol = e.selectionStartCol();
int endCol = e.selectionEndCol();

if (startLine == endLine && startCol == endCol)
{
// added here
//-->
if (!takeAllIfEmpty)
return text;
//<--

e.firstLine();
while (e.moreLines())
{
text += e.getLine()+'\r\n';
e.nextLine();
}
}
else
{
...
(the rest of the method)


3. Created the method which implements this new kind of comments:


// Insert a comment in place of the cursor
// (Example: Developer's name (Your company name) (YYYY/MM/DD) (#))
// //-->
// Your code here as it was before
// //<--
void Comments_BetweenParentheses(Editor e)
{
#define.YourCompanyName("Your company name")
str selText = EditorScripts::getSelectedText(e, false);
str selFirstLine;
int startLine = e.selectionStartLine()+1;
int startCol = e.selectionStartCol();
xppSource xppSource;
;
if(this.isEmptySelection(selText))
{
startLine = e.selectionStartLine()+1;
e.firstSelectedLine();
selFirstLine = e.getLine();

startCol = strLen(selFirstLine) -strLen(strLTrim(selFirstLine));
xppSource = new xppSource(startCol);
e.insertLines(xppSource.indent()+strFmt("// %1 ("+#YourCompanyName+") (%2) (#)", XUserInfo::find(False, curUserId()).name, date2str(today(), 321, 2, 4, 2, 4, 4))+"\n");
e.insertLines(xppSource.indent()+strFmt("//-->\n"));
e.insertLines(selText);
e.insertLines(strFmt(xppSource.indent()+"//<--\n"));
e.gotoLine(startLine+1);
e.gotoCol(startCol+1);
}
else
{
startCol = e.columnNo();
xppSource = new xppSource(startCol);
e.insertLines(strFmt("// %1 ("+#YourCompanyName+") (%2) (#)", XUserInfo::find(False, curUserId()).name, date2str(today(), 321, 2, 4, 2, 4, 4))+"\n");
e.insertLines(xppSource.indent()+strFmt("//-->\n"));
e.insertLines(strFmt(xppSource.indent()+"//<--\n"));
e.gotoLine(e.currentLineNo()-1);
e.gotoCol(50);
e.insertLines(strFmt("\n"+xppSource.indent()));
}
}




So, after compilation you can use the new comments style.



after commenting



Just to be on the safe side I place here the link to the whole project file CommentParentheses.xpo

книга Разработка бизнес-приложений в Microsoft Business Solutions - Axapta версии 3.0



С этой книги я начал изучение ERP-системы MS Axapta, во многом благодаря ей я нашёл первую работу в Канаде, и по сей день, она является наиболее востребованной среди прочих книг на моём столе для разработки для всех версий MS Dynamics: 3.0 4.0 и 2009.

Книга написана одновременно и как справочное пособие по архитектуре, среде разработки и языку X++, и параллельное описание реализации конкретного проекта "Управление гостиницей".
На примере последнего и разбираются варианты использования той или иной функциональности.

Вообще, примеры - это самая сильная часть любого руководства разработчика, и данная книга - отличный образец того, как это нужно делать: здесь можно найти не только соответствующие Best Practice стандартные паттерны программирования, которые особенно важно усвоить вначале работы с системой, но и такие приёмы, как, скажем работа с COM - Axapta Business Connector или организация многомерных массивов.

Название третьей главы "Что должен знать эксперт" говорит само за себя.

Мои любимые параграфы те, где речь идёт о создании и вызове сущностей системы, таких как формы, меню, запросы и так далее, напрямую из кода.

Особенно приятно, что она написана русскими ребятами на хорошем русском языке.

В целом, оценивая этот беспрецедентный по охвату материала, стройности и стилю изложения и оригинальности концепции труд, можно сказать, что данная книга является краеугольным камнем в построении карьеры разработчика MS Dynamics.

Wednesday, February 18, 2009

XPO file viewer

When you deal with a pile of Axapta project files (xpo-files) it might be very useful to take a look at what it consists of.

For this goal, I created a small application that allows to see the content of an XPO file in Tree view as you got used to see during the import procedure in AX.

No need anymore to load AX, just launch XPOViewer.exe (from XPOViewer.zip archive) and open the file you want to see. You can also start this application by double-click on files having set it as default system action: by xpo files association.


Loading large project files can take much time, so, be patient and enjoy the progress bar.

In the Tree view you can copy any branch text to your clipboard by Ctrl-C key combination or from the context menu.

Friday, December 19, 2008

Synchronisation Error: Cannot execute a data definition language command on ().

It is really useful job to cure this senseless error. Taken from russian Axapta forum.

Friday, December 12, 2008

How to add a custom report from scratch in OnTime2008 with behaviour of standard reports

This is about OnTime2008, the system used for development management. A small issue occurred during design a Customer report: we could not pass the selected project in the project tree as a parameter for SQL statement.

1. Create your stored procedure in MS SQLServer. You can easily use existing SP as a base, i.e. spS_Projects_Summary.Otherwise, you can just add an SQL-statement later in design time inOnTime2008.

2. Create and execute a command like thefollowing. Pay attention to the group of reports where you want to add your report to.
You can either add your xml-defined report design here or define it later in design time in OntIme2008.

HINT: The easiest way is just to create a copy of a standard report looking similar to one you want to create and copy-paste its xml code in MS SQL Server. It will take everything including the C# script.

USE [OnTime2008_Test]
GO

DECLARE @return_value int,
@ReportId int

EXEC @return_value= [dbo].[spI_Reports]
@ReportId= @ReportId OUTPUT,
@Name =N'LBA Deliveries', -- report name
@ReportClass= N'',
@ReportXML= N'', -- can be copied-pasted or designed later
@SqlCommand= N'LBA_spS_DeliveryReport @projectid = {CURRENT_PROJECT}', -- your storedprocedure or SQL statement
@ReportType= 4, -- group for the report: 1- defects; 2- features; 3 - tasks; 4-summaries;5 - workslog; 6 - incidents; 7 - dashboard;
@IsActive= true,
@CreatedById= 1,
@CreatedDateTime= '2008-12-12 15:23:54', -- not important
@LastUpdatedById= 1,
@LastUpdatedDateTime='2008-12-12 15:23:54' -- not important

SELECT @ReportIdas N'@ReportId'

SELECT 'ReturnValue' = @return_value

GO

3. At this stage you may launch OnTime2008 (or re-launch it in order to re-index) and open your newly created report in the approriate group of reports (Reports\Manage Reports...).
Now, just create a shortcut to the report and you can start to use it.

NOTE: Using filters depends on the report group.

The sample of xml code for the report design and the history of this issue you can find on the Axosoft forum.

Wednesday, November 19, 2008

Connection from AX to an External Database

There are a few options. We can create an ODBC connection on a local machine or just to connect directly without creating ODBC record.


For exmaple, we want to check whether some records exist in an external table. We should create a OdbcConnection with appropriate LoginProperty and permit to execute a SQL statement by means of SqlStatementExecutePermission class. 



server boolean checkExternalDB()
{
//connection parameters
#define.ExternalTableName("CustTable")
#define.ExternalFieldName("AccountNum")
#define.ExternalSQLServerName("SRVAXSQL2005")
#define.ExternalSQLDBName("DAXdb401_Standard_DEV")
LoginProperty LP = new LoginProperty();
OdbcConnection myConnection;
SqlStatementExecutePermission permission;
Statement myStatement;
str sqlStmt = "";
ResultSet myResult;
boolean ret = true;
;

LP.setServer(#ExternalSQLServerName);
LP.setDatabase(#ExternalSQLDBName);
try
{
myConnection = new OdbcConnection(LP);
}
catch
{
info("Check connection parameters. "+funcName());
ret = checkFailed(strfmt("External DB Connection error in: %1"), #ExternalSQLDBName);
}

myStatement = myConnection.createStatement();
//anything you want to get from the external table
sqlStmt = "SELECT count (RecId) FROM "+#ExternalTableName+ " where "+#ExternalFieldName + " = '" + this.AccountNum+"'";

permission = new SqlStatementExecutePermission(sqlStmt);
permission.assert();

myResult = myStatement.executeQuery(sqlStmt);
while (MyResult.next())
{
if (MyResult.getInt(1) > 0)
{
//yes, records exist in the external table
ret = checkFailed(strfmt("@LBA53"+"\n"+funcName(), strfmt("[%1].[%2].[%3]", #ExternalSQLServerName, #ExternalSQLDBName, #ExternalTableName)));
break;
}
}

CodeAccessPermission::revertAssert();

return ret;
}

MS Outlook and CRM Tasks Synchronization Issue

Recently I found out an issue with synchronization of tasks between CRM module and MS Outlook in AX4.0SP2.

It looks like MS Outlook does not understand the command and causes the following error:

Method 'sort' in COM object of class '_Items' returned error code 0x80020009 (DISP_E_EXCEPTION) which means: Propriété « Start » inconnue.


I changed the synchronizeTasksOutlookToAxapta method of SmmOutlookSync_Task class in order to fix the problem like it was done in AX2009:

taskItemsCollection.sort('[Start]', false);

to

#define.startDateProperty('StartDate')
// Turn sort and include recurrences ON to get recurring tasks
taskItemsCollection.sort(#startDateProperty, false);