Источник:
http://patrickmouwen.com/technicalde...rol-dashboard/
==============

In my main
blog post regarding Dynamics AX Retail/3rd party integration I mentioned leveraging Real Time Service to allow middleware (like Microsoft BizTalk) and 3rd party systems to report to AX on the results of their actions. As the meta data is written into the standard Dynamics AX Retail
download sessions and
upload sessions forms, these forms will now serve system administrators to have
visibility and
control even beyond their the Dynamics AX Retail CDX landscape (CDX -> see rectangle in the middle, beyond CDX -> bottom rectangle):

In this blog I’ll provide the X++ source code to enable this and I’ll mention some tiny features I added to the
download sessions and
upload sessions forms to maximize control on our 3rd party integration. First I’ll introduce you to the topic by explaining a bit more on how to extend Real Time Service for access from 3rd party systems.
How to extend Real Time Service
What I like most about Real Time Service is that it provides a single-point-of-access to any method in AX from the outside world. With ‘single-point-of-access’ I mean that with Real Time Service we don’t need to expose an endless number of services if for example we want to get customer information, create a customer and cancel an order – we can stick to 1 service only as the AX method we want to call into through the service is a
parameter on the service. So if we want to create a customer in AX we tell the service to invoke the
RetailTransactionService::newCustomer method and we provide the service with the input parameters the respective method in AX expects:

Message for calling the Real Time Service (newCustomer method) = The “sender”
AX HQ newCustomer method = The “receiver”
So basically you can call into any method in AX from 3rd party systems just by passing the right parameters and sending the information in the right message format. In a later blog I’ll provide more details in this particular area – for now I stick to mentioning some basic ‘rules of play’:
- Real Time Service is designed to call into the RetailTransactionService and RetailTransactionServiceEx classes in AX by default. Although even this is configurable in the web.config file of the RealTimeService application on IIS, I’d stick to this standard. In practice this will never block you from leveraging any method in AX. Just follow the path Microsoft is on since the AX 2012 R3 release, to leverage the methods in the RetailTransactionService and RetailTransactionServiceEx classes only as ‘gateway’ to other classes not including any business logic in itself. It basically comes down to the following structure (see left hand side):

- Before going into customization, carefully check the richness of the current RetailTransactionService class first. Microsoft has exposed more than 100 Retail related methods packed with business logic through this class. So the most common Retail operations (which are normally exposed to the native AX channels ;-)) are available. In general, it’s easy to expose existing business logic by just creating a custom ‘gateway’ method to call into existing business logic. So rule of thumb should be that minimal coding is required, otherwise you might have chosen the wrong path.
- Put all custom (‘gateway’) methods in the RetailTransactionServiceEx classes. Invoking these methods is nothing different than invoking the methods in the RetailTransactionService class except for replacing the node InvokeMethod by InvokeExtensionMethod in the example XML above.
Custom RetailTransactionServiceEx:: newRetailCDXMetaDataRecord
With this custom method (see source code below), both Retail > Inquiries > Commerce data exchange > Upload sessions and Download sessions table/forms are served. This is directed by the downloadMessage boolean field which is 1 (true) if the respective interface flow is a download flow (AX -> native AX/3rd party) and 0 (false) if the respective interface flow is an upload flow (naïve AX/3rd party). The artifacts prefixed with ‘pmo’ are discussed in the next section of this blog. First I’ll list you the input/output variables for the method – the array element type indicates what the type of parameter is that your XML message to Real Time Service requires for the variable. Note for the X++ code that I included many validations to ensure errors are not raised due to XML variable type to AX variable type conversion issues.

///
/// Method is added by PMOU (16.06.2015)
/// Method is used for creating a RetailCDXDataStoreSession record which reflects CDX meta data
/// BizTalk leverages the method to report on the result of its part of the AX/3rd party channel interface chain
/// In doing so, system administrators have complete visibility and control across the complete interface chain including integration to 3rd party channels
///
///
/// Container with entity keys
///
public
static
container newRetailCDXMetaDataRecord(
boolean downloadMessage,
RetailCDXSharePath sDataFileOutputPath,
RetailCDXDataGroupRefRecId sDatagroupRecId,
RetailConnJobId sJobId,
RetailCDXRowsAffected sRowsAffected,
RetailCDXScheduleRefRecId sScheduleRecId,
RetailCDXSessionNumber sSessionNumber,
RetailCDXDownloadSessionStatus sDownloadStatus,
pmoRetailCDXLinkedSessionRefRecId sdsLinkedSessionRecId,
RetailCDXDataStoreRefRecId sdsDataStoreRecId,
str sdsDateApplied,
str sdsDateDownloaded,
str sdsDateRequested,
RetailCDXMonDataSyncMessage sdsMessage,
RetailCDXDownloadSessionStatus sdsDownloadStatus,
RetailCDXCheckSum uCheckSum,
RetailCDXDataStoreRefRecId uDataStoreRecId,
str uDateCreated,
str uDateUploaded,
RetailCDXFileSize uFileSize,
RetailCDXHqUploadSessionID uHQUploadSessionId,
RetailConnJobId uJobId,
RetailCDXMonDataSyncMessage uMessage,
RetailCDXUploadSessionRerun uRerun,
RetailCDXSessionNumber uRerunForSessionId,
RetailCDXRowsAffected uRowsAffected,
RetailCDXScheduleRefRecId uScheduleRecId,
RetailCDXUploadSessionStatus uUploadStatus,
RetailCDXTryCount uTryCount,
RetailCDXPacketFilePath uUploadPath,
RetailCDXSessionNumber uUploadSessionId,
pmoRetailCDXLinkedSessionRefRecId uLinkedSessionRecId,
pmoRetailCDXDataSource uDataSource)
{
boolean success =
false;
str error =
”;
Counter infologline = infolog.num();
int fromLine;
str xmlResult =
”;
container tmpResult;
RetailCDXDownloadSessionRefRecId downloadSessionRecId;
RetailCDXDownloadSession retailCDXDownloadSession;
retailCDXDownloadSessionDataStore retailCDXDownloadSessionDataStore;
RetailCDXUploadSession retailCDXUploadSession;
RetailCDXUploadSessionLog retailCDXUploadSessionLog;
RefRecId sessionRecId;
RetailCDXDateApplied sdsdateAppliedUTC;
//UTCDateTime
RetailCDXDateDownloaded sdsdateDownloadedUTC;
//UTCDateTime
RetailCDXDateRequested sdsdateRequestedUTC;
//UTCDateTime
RetailCDXDateCreated udateCreatedUTC;
//UTCDateTime
RetailCDXDateUploaded udateUploadedUTC;
//UTCDateTime
try
{
fromLine = Global::infologLine();
// Validate if this is an AX inbound or outbound flow
if (downloadMessage ==
true)
{
// If SessionNumber is 0 then create a new session
if (ssessionNumber ==
0)
{
ssessionNumber = RetailCDXSessionIDGenerator::getNextSession();
}
if (ssessionNumber >
0 && sjobId && sdatagroupRecId && sdsdataStoreRecId)
{
// Populate table RetailCDXDownloadSession
ttsBegin;
retailCDXDownloadSession.clear();
retailCDXDownloadSession.initValue();
if (sDataFileOutputPath)
{
retailCDXDownloadSession.DataFileOutputPath = sDataFileOutputPath;
}
retailCDXDownloadSession.DataGroup = sdatagroupRecId;
retailCDXDownloadSession.JobID = sjobId;
if (srowsAffected >
0)
{
retailCDXDownloadSession.RowsAffected = srowsaffected;
}
if (sscheduleRecId)
{
retailCDXDownloadSession.Schedule = sscheduleRecId;
}
retailCDXDownloadSession.Session = ssessionNumber;
if (sdownloadStatus)
{
retailCDXDownloadSession.Status = sdownloadStatus;
}
retailCDXDownloadSession.insert();
sessionRecId = retailCDXDownloadSession.RecId;
ttsCommit;
// Populate table retailCDXDownloadSessionDataStore
ttsBegin;
retailCDXDownloadSessionDataStore.clear();
retailCDXDownloadSessionDataStore.initValue();
if (sdslinkedSessionRecId)
{
retailCDXDownloadSessionDataStore.pmoLinkedSession = sdslinkedSessionRecId;
}
retailCDXDownloadSessionDataStore.DataStore = sdsdataStoreRecId;
if (sdsdateApplied)
{
sdsdateAppliedUTC =
str2datetime(sdsdateApplied,
123);
retailCDXDownloadSessionDataStore.DateApplied = sdsdateAppliedUTC;
}
retailCDXDownloadSessionDataStore.Session = sessionRecId;
if (sdsdateDownloaded)
{
sdsdateDownloadedUTC =
str2datetime(sdsdateDownloaded,
123);
retailCDXDownloadSessionDataStore.DateDownloaded = sdsdateDownloadedUTC;
}
if (sdsdateRequested)
{
sdsdateRequestedUTC =
str2datetime(sdsdateRequested,
123);
retailCDXDownloadSessionDataStore.dateRequested = sdsdateRequestedUTC;
}
if (sdsmessage)
{
retailCDXDownloadSessionDataStore.Message = sdsmessage;
}
if (sdsdownloadStatus)
{
retailCDXDownloadSessionDataStore.Status = sdsdownloadStatus;
}
if (uDataSource)
{
retailCDXDownloadSessionDataStore.pmoDataSource = uDataSource;
}
retailCDXDownloadSessionDataStore.insert();
ttsCommit;
success =
true;
}
else
{
error =
‘@PMO17’;
success =
false;
}
}
else
{
// If SessionNumber is 0 then create a new session
if (uUploadSessionId ==
0)
{
// The upload session is synched from AsyncServerHeadOffice\dbo.UPLOADSESSION, so a new session ID should not interfere with the SQL ID range
uUploadSessionId = RetailCDXUploadSession::getNextBizTalkSession();
}
if (uUploadSessionId >
0 && uJobId && uDataStoreRecId)
{
// Populate table RetailCDXUploadSession
ttsBegin;
retailCDXUploadSession.clear();
retailCDXUploadSession.initValue();
if (uUploadPath)
{
retailCDXUploadSession.UploadPath = uUploadPath;
}
retailCDXUploadSession.DataStore = uDataStoreRecId;
retailCDXUploadSession.JobId = uJobId;
if (uRowsAffected >
0)
{
retailCDXUploadSession.RowsAffected = uRowsAffected;
}
if (uScheduleRecId)
{
retailCDXUploadSession.Schedule = uScheduleRecId;
}
retailCDXUploadSession.UploadSessionId = uUploadSessionId;
if (uUploadStatus)
{
retailCDXUploadSession.Status = uUploadStatus;
}
if (uCheckSum)
{
retailCDXUploadSession.CheckSum = uCheckSum;
}
if (uDateCreated)
{
uDateCreatedUTC =
str2datetime(uDateCreated,
123);
retailCDXUploadSession.DateCreated = uDateCreatedUTC;
}
if (uDateUploaded)
{
uDateUploadedUTC =
str2datetime(uDateUploaded,
123);
retailCDXUploadSession.DateUploaded = uDateUploadedUTC;
}
if (uFileSize)
{
retailCDXUploadSession.FileSize = uFileSize;
}
if (uHQUploadSessionId)
{
retailCDXUploadSession.HqUploadSessionId = uHQUploadSessionId;
}
if (uMessage)
{
retailCDXUploadSession.Message = uMessage;
}
if (uTryCount >
0)
{
retailCDXUploadSession.TryCount= uTryCount;
}
if (uRerun >
0)
{
retailCDXUploadSession.Rerun= uRerun;
}
if (uRerunForSessionId)
{
retailCDXUploadSession.RerunFor = uRerunForSessionId;
}
if (uDataSource)
{
retailCDXUploadSession.pmoDataSource = uDataSource;
}
retailCDXUploadSession.insert();
ttsCommit;
// Populate table RetailCDXUploadSessionLog
ttsBegin;
retailCDXUploadSessionLog.clear();
retailCDXUploadSessionLog.initValue();
retailCDXUploadSessionLog.DataStore = uDataStoreRecId;
if (uDateCreated)
{
uDateCreatedUTC =
str2datetime(uDateCreated,
123);
retailCDXUploadSessionLog.DateCreated = uDateCreatedUTC;
}
if (uMessage)
{
retailCDXUploadSessionLog.Message = uMessage;
}
if (uUploadStatus)
{
retailCDXUploadSessionLog.Status = uUploadStatus;
}
retailCDXUploadSessionLog.UploadSessionId = uUploadSessionId;
retailCDXUploadSessionLog.insert();
ttsCommit;
success =
true;
}
else
{
error =
‘@PMO17’;
success =
false;
}
}
}
catch(Exception::Error)
{
ttsabort;
error = RetailTransactionService::getInfologMessages(fromLine);
RetailTracer::Error(
‘RetailTransactionServiceEx’,
funcName(),error);
success =
false;
}
tmpResult = [success, error];
return tmpResult;
}
Enhancements to the Download session and Upload session form
In the
Upload session form, the
Message field is not visible by default. As this field will contain any positive or negative feedback from our middleware or 3rd party system, this is the first thing to change:

As shown in the picture, in both
Upload and
Download session form I’ve added the Origin field which indicates which link of the interface chain is reporting to us (see second column). Last but not least I’ve added a
Linked download session field to the
Download session form which shows which session (read: record in the Download session form) the current record followed up on. In this way, you can easy filter the form to have all the meta data as reported by the different chains of the complete interface flow in one overview.
I hope this has shown you how powerful Dynamics AX for Retail can also be leveraged for 3rd party sales channel integrations.
Happy DAX’ing!
Patrick
Het bericht
Dynamics AX Retail 3rd party POS and E-commerce integration – Control dashboard verscheen eerst op
Patrick Mouwen.
Источник:
http://patrickmouwen.com/technicalde...rol-dashboard/