Показаны сообщения с ярлыком Axapta. Показать все сообщения
Показаны сообщения с ярлыком Axapta. Показать все сообщения

пятница, 10 июня 2011 г.

AIF exception message

Hello colleagues.

My new article is about error messages which AIF sends to web service consumer application. If exception appeared inside AX business logic while web service performs a request then a client will get a message like "Request Failed. See the Exception Log for details.". It is not the transparent approach, is it. I was requested to resolve this issue in order to provide Web service consumer with detailed information about an error. After short investigation I have figured out that modification should be done in the handleProcessingException() method of the AifRequestProcessor class.

static private AifXml handleProcessingException(AifMessage message, AifInfoLog aifInfoLog)
{
SysExceptionLog exceptionLog;
AifXml faultXml;
AifMessage originalMessage;
;
// We have to get the faultXml first, otherwise doing a infolog.cut() will clear
// the fault object from infolog.
/* I have commented this block of code
if( message && AifEndpoint::propagateErrors(message.sourceEndpointId()) )
{

faultXml = AifFault::faultXml(aifInfoLog.getLastMessage());
}
else
{
faultXml = AifFault::faultXml("@SYS94277");
}*/

faultXml = AifFault::faultXml(infoLogStr(aifInfoLog.getInfoLogData())); // I have add this record

//Write entries to the Exception Log
exceptionLog = new SysExceptionLog();
exceptionLog.writeInfoLogData(strfmt("@SYS95172"), aifInfoLog.getInfoLogData());
aifInfoLog.clearLast();

// Set message status to Error if not processed yet
// The message will exist only if the message has been created, if
// any exception was thrown from processInboundMessage() before the message was created,
// the below call (AifMessageManager::update()) will fail, so we have additional check here.
if( message
&& message.messageId()
&& (!AifMessageManager::isNewMessage(message.messageId())))
{
originalMessage = AifMessageManager::read(message.messageId());
// If message in already in processed or error state, then leave it as is.
if ((originalMessage.status() != AifMessageStatus::Processed) && (originalMessage.status() != AifMessageStatus::Error))
{
originalMessage.status(AifMessageStatus::Error);
AifMessageManager::update(originalMessage, classstr(AifRequestProcessor), true);
}
}

return faultXml;
}

Here is the code of infoLogStr() method:

public static str infoLogStr(InfologData _infologData)
{
str ret;
SysInfoLogEnumerator infoLogEnum = SysInfoLogEnumerator::newData(_infologData);
SysInfologMessageStruct infoMessageStruct;
;
while(infoLogEnum.moveNext())
{

infoMessageStruct = SysInfologMessageStruct::construct(infoLogEnum.currentMessage());

if (ret)
ret += '\r\n';

ret += strFmt('%1: %2',
infoMessageStruct.preFixTextElement(infoMessageStruct.prefixDepth()),
infoMessageStruct.message());
}

return ret;
}

I hope this post will be usefull.
Best regards.

вторник, 13 мая 2008 г.

Be careful whith Collections and Maps in Axapta

Let`s review block of code listed below.

List list = new List(Types::String);

ListIterator iterator;
;
list.addEnd("a");
list.addEnd("b");
list.addEnd("c");
list.addEnd("d");

iterator = new ListIterator(list);

while (iterator.more())
{
if (iterator.value() == "b")
list.addEnd("e");

iterator.next();
}

info(list.toString());

There is instance of List class retaining arbitrary string values. ListIterator class is instantiated for traversing through elements in the list. What will happen when we try to add a new element in the list inside iteration block? New element will be added to collection! In Java for iterators implemented other behavior. If an iterator is obtained, modifying the underlying collection will throw a ConcurrentModificationException. Pay attantion to this difference.

среда, 30 апреля 2008 г.

Write InfoLog to database

There are several batch tasks running on the schedule in our company. They send many messages to InfoLog. Usually I am interesting messages of some type. It is not convenient scroll all messages in SysInfologBrowser form in search of required. I decided to implement the method for writing InfoLog to the database. After investigation of the Info class I wrote code listed below.

protected Log logTxt()

{

#resAppl

#Define.UserTab('\t')

Integer fromIdx = transLogPoint + 1;

Integer toIdx = infoLog.num();

SysInfoLogEnumerator enum = SysInfologEnumerator::newData(infoLog.copy(fromIdx, toIdx));

Log logTxt;

DictEnum dictEnum = new DictEnum(enumNum(Exception));
;
while (enum.moveNext())
{

logTxt += strFmt("%1 \t %2\r\n",

dictEnum.index2Name(enum.currentException()),
strRem(enum.currentMessage(), #UserTab));
}

transLogPoint = toIdx;

return logTxt;

}

Variable transLogPoint keep the value of the last message index before start batch task.

Why debit and credit turnovers different in Ledger and Inventory modules?

I want to share my thoughts about inventory closing functionality. I had made this research since time I took part in Axapta implementation projects. For all customers our developer team extended functionality of the inventory turnover report. After report modification users could receive detailed financial data in the inventory module. But there is one small issue. Financial managers and accountants asked me why turnovers were different in Ledger and Inventory modules. After investigation I found the cause of problem. There is no field Correct in InventTrans table like in LedgerTrans. That is why transactions are different for credit note in Ledger and Inventory modules. And inventory closing doesn’t create ledger transactions with Correct sign. We suggested correcting turnovers in Ledger module after inventory closing by manually creating additional correctional transactions. What do you think about it?

вторник, 29 апреля 2008 г.

Null value for ADO command parameter

Now I whith my colleagues work on integration Axapta with the other business application named M&F (Management and Finance). Our company uses M&F for more than eight years and now it is time for new ERP system. This application has 2-tier architecture, and its business logic is on the server side. We use stored procedure API for document exchange from Axapta to M&F. Some days ago I tried to call stored procedure on MS SQL Server from X++. For several parameters it was necessary to set null value. At first I instantiated COMVariant like this:

COM parameter = new COM("ADODB.Parameter");

COMVariant nullParam = new COMVarian(ComVariantInOut::In, ComVariantType::VT_NULL);

;

parameter.name("@paramName");

parameter.type(#adInteger);

parameter.value(nullParam); // This method throw exception!

After several hours research I found decision of this problem:

COM parameter = new COM("ADODB.Parameter");

nullParam = new COMVariant();

;

parameter.name("@paramName");

parameter.type(#adInteger);

nullParam.variantType(ComVariantType::VT_NULL);

parameter.value(nullParam); // This method doesn`t throw exception now!

I think problem is in constructor of the COMVariant class. What is your opinion?