Showing posts with label AIF. Show all posts
Showing posts with label AIF. Show all posts

Wednesday, 15 June 2016

"The endpoint does not exist or the action is not allowed" on Payment journal voucher send

Just a quick post for non-developer who hit this error and looking for solution.

If you're setting up AIF Outbound port for Payment journal, you'll need to add the "LedgerVendorPaymentService.find" operation to the port.

Without this port, when you click on the "Send..." button on the Payment journal voucher, you'll first get the error "No endPoints are configured for the action".


But the "Send document..." dialog will still shows up, and if you continue to select the Port name and click "OK", you'll get the error "The endpoint does not exist or the action is not allowed".



To fix this issue:

  1. Go to: System administration > Setup > Services and Application Integration Framework > Outbound ports
  2. Select the respective port name and click “Deactivate”
  3. Click on “Service operations” button under the “Service contract customizations” FastTab
  4. Double click on the “LedgerVendorPaymentService.find” service operation under the “Remaining service operations” list to add it into the “Selected service operations”
  5. Close the form
  6. Click “Activate” button to activate the Outbound port again


Friday, 20 May 2016

Find AIF service class name by Axd document class name

Just a quick snippet to find AIF service class name by Axd document class name.


static void GetAxdClassNameByServiceName(Args _args)
{
    #avifiles
    str                     mySearchAxdName = "AxdCountingJournal"; //Change this to your Axd class name
    List                    list;
    ListEnumerator          listEnumerator;
    SysDictClass            sysDictClass, serviceDictClass;
    AxdWizardParameters     axdWizardParameters;
    int                     progressTotal, progressCount;
    SysOperationProgress    progressBar;
   
    sysDictClass = new SysDictClass(classnum(AifDocumentService));
    list = sysDictClass.extendedBy();
   
    progressTotal = list.elements();
    progressBar   = SysOperationProgress::newGeneral(#aviUpdate, 'Axd/service class search', progressTotal);
   
    listEnumerator = list.getEnumerator();
    while (listEnumerator.moveNext())
    {
        serviceDictClass = new SysDictClass(listEnumerator.current());
       
        progressCount++;
        progressBar.incCount();
        progressBar.setText(strfmt("Searching: %1 of %2 (%3)", progressCount, progressTotal, serviceDictClass.name()));       
        progressBar.update(true);
       
        if (serviceDictClass.id() != classNum(AifGenericDocumentService))
        {
            axdWizardParameters = AifServiceClassGenerator::getServiceParameters(serviceDictClass.name());
           
            if(axdWizardParameters && axdWizardParameters.parmName() == mySearchAxdName)
            {
                info(strFmt("Aif service class name: %1", axdWizardParameters.parmAifServiceClassName()));
                info(strFmt("Document name: %1", axdWizardParameters.parmAifEntityClassName()));
                info(strFmt("Axd name: %1", axdWizardParameters.parmName()));
                info(strFmt("Query name: %1", axdWizardParameters.parmQueryName()));
               
                break;
            }
        }
    }
   
    /*
    //Use this if you know the Document class name and wanted to find the Axd class name
   
    str                     documentClassName = "LedgerGeneralJournal";
    SysDictClass            documentDictClass;
    AifDocument             documentInstance;
    AxdBase                 axdBase;
   
    documentDictClass = new SysDictClass(className2Id(documentClassName));
    documentInstance = documentDictClass.makeObject();
    axdBase = documentInstance.getAxdInstance();
   
    info(strFmt("Document name: %1", documentClassName));
    info(strFmt("Axd name: %1", classId2Name(classIdGet(axdBase))));
    info(strFmt("Query name: %1", axdBase.getQueryName()));
    */
}

Friday, 8 May 2015

AIF process stuck / never ending (due to AIFResponse deletion)

Scenario of the issue
  • Created a document service (Eg. TableA) and Inbound port to test it
  • While running the test, the receive (AifGateWayReceiveService) is OK, but the processing (AifInboundProcessingService) seems to stuck there / never ending

In details
  • Start up 2 AX client, Eg ClientA and ClientB.
  • ClientA: The testing starts with getting the Inbound port (file adaptor) and XML file ready
  • Dump the XML into the inbound folder
  • ClientA: Run a simple job which contain this line new AifGateWayReceiveService().run();
  • ClientA: Check "Queue manager" (Path: System administration > Periodic > Service and AIF) and confirmed the message has gone in
  • ClientB: Run another simple job which contain this line new AifInboundProcessingService().run();
  • ClientA: Check the "Queue manager" and confirmed the line is gone and a new record has been inserted into the table used by the document service (Eg. TableA)
  • ClientB: The job seems not finishing, AX is frozen and not responding

Below is a sample of the simple job used in above steps (just toggle around the options).

boolean runReceive = true,
        runProcess = false;
    
if(runReceive)
{
    new AifGateWayReceiveService().run();
}
    
if(runProcess)
{
    new AifInboundProcessingService().run();
}


Investigation result
The frozen isn't actually hanging, instead, it is running some record deletion, which took AGES, hence, not responding.

Below is the Trace Parser screenshot showing the trace file captured for around 30 seconds.

Within this short period, there're thousands of calls to database server for a DELETE statement.

This DELETE statement came from the AIF which tries to delete the expired AIFResponse records.



This DELETE statement supposed to delete any records that's older than the expired datetime (used today's datetime minus the AIFGlobalSettings.ResponseCacheLifetime value). Typically a 24 hours timeframe is a common value. But this table contains millions of records (up to 2 years old of data is in this table).

The solution is to get rid to this data from SQL. Since this is development environment, truncate table would do. But if this production environment, it would need more care on how the data is deleted (performance, time of performing the deletion, recover mode & backup chain, etc).

Thursday, 2 October 2014

Manually run specific AIF port

To manually run a specific AIF inbound port (File adapter), the "AifImportUtil::processFile()" static method can be used.

It accept two parameters:
1. Input file name
2. Port name

Eg. AifImportUtil::processFile("\\\\serverName\\sampleFile.csv", 'SampleInboundPortName');

AIF Inbound port error - Failed to create a session; confirm that the user has the proper privileges to log on to Microsoft Dynamics

Area: AIF
Error: Failed to create a session; confirm that the user has the proper privileges to log on to Microsoft Dynamics

We have a few AIF inbound port setup (File adapter), tested and working.
But when user put in the same file, the process failed and we're getting the error mentioned above.

The reason was due to the user who put the file into the inbound port folder is not an AX user.

AIF is using the file owner as the submitting user and this is the user who caused the error.

To view:
  • File owner: Right click on the file > Properties > Details (tab) > Owner
    *Alternatively, open the folder in Windows Explorer, change to "Details" view, add the "Owner" column.
  • Submitting user: System administration > Periodic > Services and Application Integration Framework > Queue manager > Details (tab) > Users (group) > Submitting user