Quantcast
Channel: Thomas Widmer's D365 Blog
Viewing all 53 articles
Browse latest View live

Reset program cache file for all clients

$
0
0

I had a problem with some clients running on old code (e.g. experiencing bugs that have already been fixed).

The following job resets the GUID which in turn forces all clients to create a new program cache file (AX_*.auc). A restart of the AOS is required.

static void forceNewAUC(Args _args)
{
    #AiF
    SysSQMSettings sysSQMSettings;
    ;
    ttsbegin;
    update_recordset sysSQMSettings setting GlobalGUID = str2Guid(#EmptyGuidString);
    ttscommit;
    info("Restart the AOS Service to generate a new GlobalGUID.");
}

(Source: http://blogs.msdn.com/emeadaxsupport/archive/2010/01/25/identical-ax-2009-auc-file-created-for-multiple-ax-installations.aspx)

Another option would be adding the following to the Info.startupPost() method, however I’m not sure if this is a cleaver thing to do routinely, but if you cannot restart the AOS it is you only option.

xSession::removeAOC();
SysTreeNode::refreshAll();
SysFlushDictionary::doFlush();
SysFlushAOD::doFlush();
xSession::updateAOC();

(Source: http://dynamics-ax.blogspot.com/2006/04/flush-aos-cache-from-code.html)



Report Print Preview: “Go to main table” link for display method fields

$
0
0

Situation:
A report containing e.g. PurchParmLine.itemId() will not show the orange hyperlink in the print preview screen that allows the user to jump to the main table.

Solution:
To make add a link to a display method field on a report you must replace the display method field by a temporary table datasource. Populate the desired field and send the temporary datasource.

public void executeSection //e.g. located in PurchParmLine body
{
    InventTable tmpPrintItemId; //any table with the ItemId field will do
    ;
    tmpPrintItemId.ItemId = PurchParmLine.itemId();
    element.send(tmPrintItemId);
    super();
}

Now you can add a Field with Properties Table = Inventtable and DataField = ItemId, which will print the contents of PurchParmLine.itemId() and will have the orange hyperlink in the print preview that allows the user to jump to the main table.

See also msdn How to


Powershell script: Copy DEV Layers to LIVE

$
0
0

The following Powershell script copies the AX2009 DEV Layers to LIVE thereby checking that the services have been stopped and also copying the previous layers into old and backing up old in subfolders of old:

[void][System.Reflection.Assembly]::Load(“System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″)
$AXPATH_DEV = “C:\Program Files\Microsoft Dynamics AX\50\Application\Appl\AX09_TEST”
$AXPATH_DEV_OLD = “C:\Program Files\Microsoft Dynamics AX\50\Application\Appl\AX09_TEST\old”
$AXPATH_PROD = “C:\Program Files\Microsoft Dynamics AX\50\Application\Appl\AX09_LIVE”
$AXPATH_PROD_OLD = “C:\Program Files\Microsoft Dynamics AX\50\Application\Appl\AX09_LIVE\old”
$LABELFILES = “axsa*.ald”
$LAYERFILES = “axcus*.aod”
function copyAXAppl
{
#DEV and PROD services must be stopped
    if((get-service -name AOS50?01).status -eq “Stopped”)
    {
       
if((get-service -name AOS50?02).status -eq “Stopped”)
       
{
#CREATE PROD\OLD BACKUP DIR (YYYYMMDD)
           
if(-not (test-path (join-path $AXPATH_PROD_OLD (get-date -uformat “%Y%m%d”))))
            {
                new-item -path $AXPATH_PROD_OLD -name (get-date -uformat “%Y%m%d”) -itemtype directory
            }  
#BACKUP PROD (only CUS Files)
            (dir -path $AXPATH_PROD -name $LABELFILES ) |
                foreach-object {copy $_.pspath (join-path $AXPATH_PROD_OLD (get-date -uformat “%Y%m%d”)) }
            (dir -path $AXPATH_PROD -name $LAYERFILES) |
                foreach-object {copy $_.pspath (join-path $AXPATH_PROD_OLD (get-date -uformat “%Y%m%d”)) }
#COPY PROD\OLD\{14 days old} -> PROD\OLD
            if(test-path (join-path $AXPATH_PROD_OLD (get-date (get-date).addDays(-14) -uformat “%Y%m%d”)))
            {
                (dir -path (join-path $AXPATH_PROD_OLD (get-date (get-date).addDays(-14) -uformat “%Y%m%d”)) -name “*.ald” ) |
                    foreach-object {copy $_.pspath $AXPATH_PROD_OLD }
                (dir -path (join-path $AXPATH_PROD_OLD (get-date (get-date).addDays(-14) -uformat “%Y%m%d”)) -name “*.aod” ) |
                    foreach-object {copy $_.pspath $AXPATH_PROD_OLD }
            }
#CREATE DEV\OLD BACKUP DIR (YYYYMMDD)
            if(-not (test-path (join-path $AXPATH_DEV_OLD (get-date -uformat “%Y%m%d”))))
            {
                new-item -path $AXPATH_DEV_OLD -name (get-date -uformat “%Y%m%d”) -itemtype directory
            }  
#BACKUP DEV (only CUS Files)
            (dir -path $AXPATH_DEV -name $LABELFILES ) |
                foreach-object {copy $_.pspath (join-path $AXPATH_DEV_OLD (get-date -uformat “%Y%m%d”)) }
            (dir -path $AXPATH_DEV -name $LAYERFILES) |
                foreach-object {copy $_.pspath (join-path $AXPATH_DEV_OLD (get-date -uformat “%Y%m%d”)) }
#COPY DEV –> DEVOLD
            (dir -path $AXPATH_DEV -name “*.ald” ) |
                foreach-object {copy $_.pspath $AXPATH_DEV_OLD }
            (dir -path $AXPATH_DEV -name “*.aod” ) |
                foreach-object {copy $_.pspath $AXPATH_DEV_OLD }

#COPY DEV->PROD (only CUS Files)
            (dir -path $AXPATH_DEV -name $LABELFILES ) |
                foreach-object {copy $_.pspath $AXPATH_PROD }
            (dir -path $AXPATH_DEV -name $LAYERFILES ) |
                foreach-object {copy $_.pspath $AXPATH_PROD }
        }
        else
        {
            [System.Windows.Forms.MessageBox]::Show(“First stop ‘” + (get-service -name AOS50?02).Displayname + “‘”)
         }
    }
    else
    {
           [System.Windows.Forms.MessageBox]::Show(“First stop ‘” + (get-service -name AOS50?01).Displayname + “‘”)
    }
}

Save the script above in your Powershell profile (see http://msdn.microsoft.com/en-us/library/bb613488(v=vs.85).aspx).

Run the script using a batch file containing

powershell copyAXappl


Report Print Preview: “Go to main table” link for display method fields

$
0
0

Situation:
A report containing e.g. PurchParmLine.itemId() will not show the orange hyperlink in the print preview screen that allows the user to jump to the main table.

Solution:
To make add a link to a display method field on a report you must replace the display method field by a temporary table datasource. Populate the desired field and send the temporary datasource.

public void executeSection //e.g. located in PurchParmLine body
{
    InventTable tmpPrintItemId; //any table with the ItemId field will do
    ;
    tmpPrintItemId.ItemId = PurchParmLine.itemId();
    element.send(tmPrintItemId);
    super();
}

Now you can add a Field with Properties Table = Inventtable and DataField = ItemId, which will print the contents of PurchParmLine.itemId() and will have the orange hyperlink in the print preview that allows the user to jump to the main table.

See also msdn How to


SQL Script: After Restore from PROD to TEST

$
0
0

Do you want PROD data in your TEST System? Easy, just restore a backup of PROD into your TEST-DB. Run the following script to clean up some AOS specific data:

Update [AX09_TEST].[dbo].[BatchServerGroup] set SERVERID = ’01@SRVAOS1′  where SERVERID = ’02@SRVAOS1′
–01: DEV, 02: PROD, 03: MIG

Update [AX09_TEST].[dbo].[BATCHSERVERCONFIG] set SERVERID = ’01@SRVAOS1′  where SERVERID = ’02@SRVAOS1′
–01: DEV, 02: PROD, 03: MIG

Update [AX09_TEST].[dbo].[SYSSERVERCONFIG] set SERVERID = ’01@SRVAOS1′ , SERVERGUID = newid() where SERVERID = ’02@SRVAOS1′
–01: DEV, 02: PROD, 03: MIG

Update [AX09_TEST].[dbo].[Batch] set SERVERID = ’01@SRVAOS1′  where SERVERID = ’02@SRVAOS1′
–01: DEV, 02: PROD, 03: MIG

delete [AX09_TEST].[dbo].[SYSCLIENTSESSIONS]

–the following has nothing to do with the restore to TEST
–remove obsolete [SYSCLIENTSESSIONS] from PROD

select * from [AX09_LIVE].[dbo].[SYSCLIENTSESSIONS] where STATUS = 0

delete [AX09_LIVE].[dbo].[SYSCLIENTSESSIONS] where STATUS = 0


Fetch number of records in a FormDataSource (e.g. of a Grid)

$
0
0

SysQuery::getTotal works fine, but the trick is how to handle temporary data sources where getTotal does not work:

if(!formDataSource.curser().isTmp())
{
    recordCount = SysQuery::getTotal(formDataSource.queryRun());
}
else
{
    while(!formDataSource.allRowsLoaded())
    {
        formDataSource.getNext();
    }
    recordCount = formDataSource.numberOfRowsLoaded();
}

Now recordCount contains the number of Records in the FormDataSource irrespective of the Tmp status of the data source. Of course the whole tmp-data source has been loaded in the process, which might be an issue in some cases.


Global::str2con() converts strings to numbers, if it can.

$
0
0

I don’t like that the function Global::str2con(str _value, str 10 _sep = ‘,’) converts strings to numbers, if it can. It does this on a field by field basis, i.e. the resulting container might be a mixed bag of strings and numbers, which is difficult to process.

I added my own function to avoid this:

public static container str2strCon(str _value, str 10 _sep = ‘,’)
{
    #define.SC(“¶”) //special character
    int length = strlen(_value), sepLength = strlen(_sep);
    int i = 1;
    int j = strscan(_value, _sep, 1, length);
    container ret;
    ;
    while (j)
    {
        ret += (substr(_value, i, j-i));
        i = j+sepLength;
        j = strscan(_value, _sep, i, length);
    }
    ret += strreplace((substr(_value, i, length-i+1)),#SC,_sep);
    return ret;
}

While we’re at it:
The reverse function con2str does not guarantee reversibility – if a component of the container contains the separator, then the reversing function (str2Con) will result in a larger container. So I added a similar function strCon2str() to generate strings from a container while removing the separator character from strings in a container. This guarantees the reversibility of the function. My str2strCon() function above restores the separator character in the component-strings.

static str strCon2str(container c, str 10 _sep = ‘,’)
{
    #define.SC(“¶”) //special character
    str ret, s;
    int i;
    ;
    for (i=1; i<= conlen(c); i++)
    {
        s = conpeek(c,i);
        ret = (ret?ret + _sep:”") + strreplace(s,_sep,#SC);
    }
    return ret;
}


Missing image resource browser

$
0
0

My only trick to find the resource number of an image is to use the resource browser.

In one installation I missed the resources browser (which should be found in the Menu: Tools –> Development tools –> Embedded Resource)

I didn’t find out why the menu option was missing but the workaround is easy:
in the AOT you can look for the form SysImageResources, which still works fine:

SNAP



Excel Sheetname Function

$
0
0

Issue description

As many of you might have found out, you can get the sheet name using the formula

=MID(CELL("filename");FIND("]";CELL("filename"))+1;99)

The issue with this solution is however that the sheet name does not refresh immediately when changing sheet.

The following screenshots show how this as well as a proposed function you can add as add-in:

Sheet 1: all good!
image

Sheet 2: field A1 has not refreshed
image

Sheet 2: after a press of F9 A1 is recalculated (Note that setting the recalculation options to “automatic” does not help.)
image

Proposed solutions

  • Get Microsoft to add a new function “SHEETNAME”
  • Add a custom function “SHEETNAME” yourself.
  • Create custom function “SHEETNAME

    Create a new Excel File

    Go to the VB-Editor (Alt-F11)

    Create a new module containing the following code:

    Function SHEETNAME(reference)
        SHEETNAME = reference.Parent.Name
    End Function

    Go back to the normal Excel View

    Save As, pick Type “Excel Add-In (*.xlam)”, the path will change automatically, Save
    image

    Add the Add-In in Excel Options:
    image

    Browse for the file you created an add the Add-In
    image

    Now the new function “SHEETNAME” can be used.

    Usage

    =SHEETNAME(reference)

    It’s however reasonable to add an IFERROR to capture the error caused by not having the custom function – of course the updating issue of the standard method will occur.

    =IFERROR(SHEETNAME(A1);MID(CELL("filename");FIND("]";CELL("filename"))+1;99))

    Sheet 1: without Add-in
    image


    Controlled Release of new Developments

    $
    0
    0

    Issue

    Various Developments are in different stages of development, testing and release.
    It can be challenging to keep track of all changes and keep the different systems in sync.

    Release management option 1: Use XPOs

    Process

    • Development system (DEV): Development w/o special consideration of release process
      When done, move completed developments via xpo to TEST.
    • Test system (TEST): Testing
      When done, move successfully tested object to PROD (or REL) using xpo
    • Release system (REL): Create release layer if desired
      When done move Layer to PROD.
    • Productive system (PROD): Active code base

    Issues

    • Manual identification and extraction of relevant objects required
    • Three different code bases
    • Danger of object-Ids being out of sync
    • Objects can simultaneously contain modifications in different stages of development; some should be release, others not

    Release management option 2: Use configuration keys

    Process

    • Development system (DEV): Development adding configuration keys allowing to deactivate the newly created code parts. (Do not use configuration keys for Database objects – PROD, TEST and DEV databases should be identical –> Enabling/Disabling configuration keys will never result in database issues).
      When done, move entire layer to TEST (synchronization between developers required, to ensure that all have disable their changes using configuration keys.)
    • Test system (TEST): Activate Configuration Keys ready for testing; Test. Additional checks required that deactivated developments do not have unintended side effects.
      When done, move entire layer to PROD. (In some cases the code might have been release earlier, so only enabling configuration keys is required in PROD.)
    • Production system (PROD): Enable configurations keys.

    Advantages (referring to option 1)

    • Simple identification and activation using configuration keys
    • One code base
    • Identical object-ids in all systems
    • No issues in with objects simultaneously containing modifications in different stages of development.

    Disadvantages

    • Incorrectly disabled code can cause issues à additional testing required (release document needs to identify new added – but not enable code)

    My conclusion

    In my opinion the advantages of Option 2 outweigh the disadvantage of the additional “disabled”-testing required.

    Practical aspects

    Configuration key structure

    Add a configuration key parent for pending objects and one for released objects. In DEV all configurations are always enabled (this can be ensured by script – see below), in TEST only some configurations in the “Release pending” group might be enabled. In PROD, no configurations in the “Release pending” group might are enabled.

    image

    After successful testing the configuration keys are moved into the released group. Note: Moving between the “Release pending” and the “Released” group does nothing in itself – it is recommended for keeping track of the status of the various objects and can be used by scripts to identify the status of configuration keys.

    Enable DEV/TEST configuration keys after restore

    The following code enables all config keys under ReleasePending. It is useful after a restore of the PROD database into test and can be run as manually executed job or can be included in Info.startupPost() to automatically run when the current database is TEST (SysSQLSystemInfo::construct().getloginDatabase()).

    /// <summary>
    /// Activate all configuration keys under ReleasePending ==> for test system only!
    /// </summary>
    static void enableControlledReleaseConfigs()
    {
        int i;
        Dictionary dict = new Dictionary();
        SysDictConfigurationKey sDCK;
        ConfigurationKeySet configurationKeySet;
        ;
        configurationKeySet = new ConfigurationKeySet();
        configurationKeySet.loadSystemSetup();

        for (i=dict.configurationKeyCnt(); i; i–)
        {
            sDCK= new SysDictConfigurationKey(dict.configurationKeyCnt2Id(i));
            if(sDCK.parentConfigurationKeyId() == configurationKeyNum(ReleasePending))
            {
                configurationKeySet.enabled(sDCK.id(),true);
            }
        }
        SysDictConfigurationKey::save(configurationKeySet.pack());
        SysSecurity::reload(true,true,true,false);
    }


    Version Control: Enforce some, but not all Best Practice Rules

    $
    0
    0

    I’m not saying that having disabled best practice checks is desired, but it might be helpful, when enabling version control on a system with lots of legacy development, thereby still requiring some minimal best practice checks.

    The know location for enforcing all best practices in version control is here: Menu>>Tools>Development tools>>Version control>>Setup>>System settings:

    image

     

    Exclude certain best practice requirements by editing SysTreeNode.allowCheckIn:

    image


    Recreate AX2009 AIF Messages (save to file)

    $
    0
    0

    After a BizTalk mishap a customer wanted to recreate the xml files for all AIF Messages in a certain timeframe. The following job does exactly this.

    static void AIFMessagesRecreate(Args _args)
    {
        AifMessageLog   AifMessageLog;
        AifDocumentLog  aifDocumentLog;
        AifMessage      aifMessage;
        Dialog          dialog = new Dialog("Recreate AIF Messages to file");
        int             i;
        Filename        filePath;
        DialogField     dlgFilePath;
        Query           q = new Query();
        QueryRun        qr;
        QueryBuildDatasource    qbds;
        #file
        TextIo          diskFile;
        //copied and enhanced - Source AifMessage::serialize()
        AifMessageXml serialize(AifMessage message, AifDocumentXml _AifDocumentXml)
        {
            #Aif
            AifMessageXml           messageXml;
            XmlTextWriter           xmlTextWriter;
            XmlTextReader           xmlTextReader;
            AifDocumentXmlNamespace documentNamespace;
            AifXmlEncoding encoding;
            ;
            encoding = AifUtil::updateEncodingAttribute(message.encoding());
            documentNamespace = #MessageNamespace;
            xmlTextWriter = XmlTextWriter::newXml();
            xmlTextWriter.formatting(XmlFormatting::None);
            AifUtil::writeXmlDeclaration(xmlTextWriter, encoding);
            //Write the Envelope element
            xmlTextWriter.writeStartElement2(#MessageEnvelope, documentNamespace);
            //Write the Header element
            xmlTextWriter.writeStartElement(#MessageHeader);
            xmlTextWriter.writeElementString(#MessageId, guid2str(message.messageId()));
            // The source endpoint user is not sent on outbound messages for security reasons
            if (message.direction() != AifMessageDirection::Outbound)
                xmlTextWriter.writeElementString(#MessageSourceUser, message.sourceEndpointUserId());
            xmlTextWriter.writeElementString(#MessageSourceEndpoint, message.sourceEndpointId());
            xmlTextWriter.writeElementString(#MessageDestEndpoint, message.destinationEndpointId());
            xmlTextWriter.writeElementString(#MessageAction, message.externalAction());
            if(message.requestMessageId())
                xmlTextWriter.writeElementString(#MessageRequestId, guid2str(message.requestMessageId()));
            //End the Header
            xmlTextWriter.writeEndElement();
            //Write the Body element
            xmlTextWriter.writeStartElement(#MessageBody);
            try
            {
                xmlTextReader = XmlTextReader::newXml(_AifDocumentXml);
                xmlTextReader.whitespaceHandling(XmlWhitespaceHandling::None);
                //Move past the declaration
                xmlTextReader.moveToContent();
                xmlTextWriter.writeRaw(xmlTextReader.readOuterXml());
                xmlTextReader.close();
            }
            catch(Exception::Error)
            {
                //Unable to serialize the contents of the Xml property.
                throw error(strfmt('@SYS89763'));
            }
            //End the Body
            xmlTextWriter.writeEndElement();
            //End the Envelope
            xmlTextWriter.writeEndElement();
            messageXml = xmlTextWriter.writeToString();
            xmlTextWriter.close();
            return messageXml;
        }
        ;
        dlgFilePath = dialog.addFieldValue(typeId(FilePath),'C:\\Temp\\');
        if(dialog.run())
        {
            filePath = dlgFilePath.value();
            qbds = q.addDataSource(tablenum(AifMessageLog));
            qbds.addRange(fieldnum(AifMessageLog,createdDateTime));
            qbds.addRange(fieldnum(AifMessageLog,DestinationEndpointId));
            qr = new QueryRun(q);
            if(qr.prompt())
            {
                while (qr.next())
                {
                    if(qr.changed(tablenum(AifMessageLog)))
                    {
                        aifMessageLog = qr.get(tablenum(AifMessageLog));
                        select firstonly aifDocumentLog where aifDocumentLog.MessageId == aifMessageLog.MessageId;
                        aifMessage = new AIFMessage(AifMessageLog.MessageId,AifMessageLog.SourceEndpointUserId,aifMessageLog.SubmittingUserId);
                        aifMessage.destinationEndpointId(AifMessageLog.DestinationEndpointId);
                        aifMessage.sourceEndpointId(AifMessageLog.SourceEndpointId);
                        diskFile = new TextIo(filePath + guid2str(AifMessageLog.MessageId) + ".xml", #io_Write, 65001); //UTF-8
                        diskFile.write(serialize(aifMessage,aifDocumentLog.DocumentXml));
                        diskFile = null;
                        i++;
                    }
                }
            }
        }
        info(strfmt("%1 files saved",i));
    }

    GDPdU Sample Configuration

    $
    0
    0

    AX 2009 offers the GDPdU (Grundsätze zum Datenzugriff und zur Prüfbarkeit digitaler Unterlagen) Export in the German Layer for which there is a nice Description:

    Länderspezifische Funktionalität für Deutschland: GDPdU_80069A_AX2009.pdf

    However, the it left completely up to the user to start from scratch. The following is a sample GDPdU definition as a starting point for your configuration (Import using Basic>>Periodic>>Import/Export>>Import)

    Definition file: GDPdU Definition.def

    Data file: GDPdU Definition.dat


    Quick fix for posting definitions error

    $
    0
    0

    Error Message

    The source document cannot be processed until you assign a posting definitions to the source document in the Transaction posting definition form.

    Quick fix

    Simply disable posting definitions here: General ledger >> Setup >> General ledger parameters HS7ClipImage_51d16594


    Debugging AX2012

    $
    0
    0

    Yes, CIL code can be debugged in visual studio, but it’s much easer to just disable CIL and use the Morph-X debugger:

    File>>Tools>>Options>>Development>>Execute business operations in CIL ==> No

    HS7ClipImage_51ecf366



    Function to use in Queries, Filters

    $
    0
    0

    Joris on Dynamics AX Musings wrote this Blog Entry: Custom Query Range Functions using SysQueryRangeUtil

    I am slightly annoyed with myself that I have not been aware of this even though it has been available since AX 2009. The following functions can be used in any query or filter. Note that the functions are case sensitive and need to be put in brackets e.g. (currentUserId()).

     

    Current user (or roles thereof)

    • currentUserId()
    • currentEmployeeId()
    • currentBusinessRelationsAccount()
    • currentContactPersonId()
    • currentCustomerAccount()
    • currentVendorAccount()

    Dates (all but dateRange are relate to the current date and time)

    • currentSessionDate()
    • currentSessionDateTime()
    • day(int relativeDays = 0)
    • dayRange(int relativeDaysFrom = 0, int relativeDaysTo = 0)
    • greaterThanDate(int relativeDays = 0)
    • lessThanDate(int relativeDays = 0)
    • monthRange(int relativeMonthsFrom = 0, int relativeMonthsTo = 0)
    • yearRange(int relativeYearsFrom = 0, int relativeYearsTo = 0)
    • dateRange(date startDate, date endDate)

    Constants

    • currentStaticMasterPlan()

    AX2012 only

    • currentDate()
    • currentLanguageId()
    • currentUserLanguage();
    • currentWorker()
    • currentWorkerRecId()
    • currentLegalEntity()
    • currentParty()
    • advancedLedgerEntryCurrentUserFilter(boolean _createdBy)
    • advancedLedgerEntryTxtOpenDraftAll(anytype _advancedLedgerEntryTransactionStatus)
    • currentRoleHasAccessToPrivate(boolean _useCache = true)
    • currentStaticMasterPlanVersion()
    • dateRange(date startDate, date endDate)
    • lessThanUtcDate(int relativeDays = 0)
    • lessThanUtcNow()
    • greaterThanUtcDate(int relativeDays = 0)
    • greaterThanUtcNow()
    • documentStatusPurchOrderOrGreater()
    • getActiveMasterPlanVersionByPlanId(ReqPlanId _planId)
    • isDirAddressPolicyOff()
    • isPrivate()
    • pmfInventTableIsBOM()
    • pmfInventTableIsBOMFormula()
    • projActiveAll(ProjActiveAll _projActiveAll)
    • projActiveAllWIPEliminated(anytype _ProjTableActiveAll)
    • projLevels(ProjLevels _projLevels)
    • projPostedTransType(ProjPostTransViewType _projPostedTransViewType)
    • projUnpostedTransType(ProjUnpostedTransViewType _projUnpostedTransViewType)
    • salesQuotationTemplateGroupFilter(SalesQuotationFilter _salesQuotationFilter)
    • salesQuotationTypeListPageFilter(SalesQuotationTypeListPage _salesQuotationTypeListPage)
    • sessionGuid()
    • workflowDelegationFilter(WorkflowDelegationView _filter)

    As you see AX 2012 has many more predefined special ranges, many of which are not very self explanatory. These are used in the filters of the pre-filtered list pages.

    And as Joris showed, you can easily extend the list…


    Pattern: Job to delete many records

    $
    0
    0

    Pattern for efficient (i.e. use transaction for multiple deletes and use doDelete), stable (i.e. don’t make one huge transaction but commit and restart transaction periodically) and verbose (count down the number of remaining records) job to delete many records in a table.

      

    static void deleteJob(Args _args)
    {
        #define.TABLE(myTable)         //set
        #define.CONDITION(true)        //set
        #define.TRANSACTIONSIZE(100)   //set
        #TABLE #TABLE;
        int i = 1;
        ;
        while (i>0)
        {
            i=0;
            info(strfmt("%1",(select count(RecId) from #TABLE where #CONDITION).RecId));
            infolog.viewUpdate();
            ttsbegin;
            while select forupdate #TABLE where #CONDITION
            {
                #TABLE .dodelete();
                i++;
                if(i>=#TRANSACTIONSIZE)
                    break;
            }
            ttscommit;
        }
    }

    .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } .csharpcode,.csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


    Deduplication on my Windows 8 Notebook with AX Demo Hyper-V

    $
    0
    0

    After reading http://www.expta.com/2013/04/updated-blistering-fast-hyper-v-2012.html, http://www.expta.com/2013/02/windows-server-2012-deduplication-is.html and http://weikingteh.wordpress.com/2013/01/15/how-to-enable-data-deduplication-in-windows-8/ I enabled deduplication on my notebook, saving me lots of space on my precious SSD.

    It’s a pity that you cannot enable it on your boot drive, as this happens to be my largest SSD, but my secondary SSD with just 128 GB also benefited from the deduplication. I might reorganize my drives at some later stage.

    Here a short summary of the steps required for enabling deduplication on a windows 8 Notebook:

    1. Download Windows Server 2012 deduplication package
    2. In powershell run the following to install the package
      dism /online /add-package /packagepath:Microsoft-Windows-VdsInterop-Package~31bf3856ad364e35~amd64~~6.2.9200.16384.cab /packagepath:Microsoft-Windows-VdsInterop-Package~31bf3856ad364e35~amd64~en-US~6.2.9200.16384.cab /p
      ackagepath:Microsoft-Windows-FileServer-Package~31bf3856ad364e35~amd64~~6.2.9200.16384.cab /packagepath:Microsoft-Window
      s-FileServer-Package~31bf3856ad364e35~amd64~en-US~6.2.9200.16384.cab /packagepath:Microsoft-Windows-Dedup-Package~31bf3856ad364e35~amd64~~6.2.9200.16384.cab /packagepath:Microsoft-Windows-Dedup-Package~31bf3856ad364e35~amd64~en-US~6.2.9200.
      16384.cab
    3. The to enable deduplication run this powershell command
      dism /online /enable-feature /featurename:Dedup-Core /all
    4. Disable Periodic Processing because our main focus will be the deduplication of VHDs
      Set-DedupSchedule -Name "BackgroundOptimization" -Enabled $false
    5. Set minimum age to zero as VHD Files will always have recent modifications.
      Set-Dedupvolume D: -MinimumFileAgeDays 0
    6. Run Deduplication only when Hyper-V stopped
      Start-DedupJob –Volume D: –Type Optimization

    Result:
    image


    AX 2012 CU7 – Send documents to e-mail addresses defined on the customer.

    $
    0
    0

    Probably every AX consultancy has programmed a module to send customer documents by email using addresses defined on the customer. With CU7 you can finally can do this in Standard AX:

    Define a primary e-mail on the customerclip_image002

    In the print dialog select “Customer primary contact”clip_image004

    Result: The e-mail is sent to the primary e-mail address defined on the customer.

    The settings are now saved in the print destinations and do not need to be changed anymore. When the primary e-mail address is changed, the next e-mail will automatically be sent to the new address.

    Even better, once the print settings have been saved, all sales orders will pick up their respective customer emails without further settings needed.

    Follow the instructions here http://blogs.msdn.com/b/axsupport/archive/2013/02/05/emailing-customer-invoices-from-a-batch.aspx, you will be able to automatically send you confirmations and invoices by email using email addresses defined on the customer.

    Even better: Define e-mail addresses for different documents by applying customizable purposes:clip_image006

    Select purpose in the print dialog:
    clip_image008

    Final Note: If the defined e-mail is missing you will get the following error.clip_image002[5]


    List of predefined AX 2012 Workflows

    $
    0
    0
    Category Workflow Description
    Accounts payable Vendor bank remittance journal workflow Use this type to create approval workflows for vendor bank remittance journals
    Accounts payable Vendor disbursement journal workflow Use this type to create approval workflows for vendor disbursement journals
    Accounts payable Vendor draw promissory note journal workflow Use this type to create approval workflows for vendor draw promissory note journals
    Accounts payable Vendor invoice approval journal workflow Use this type to create approval workflows for vendor invoice approval journals
    Accounts payable Vendor invoice journal workflow Use this type to create approval workflows for vendor invoice recording journals
    Accounts payable Vendor invoice line workflow Use this type to create review workflows for vendor invoice lines
    Accounts payable Vendor invoice register journal workflow Use this type to create approval workflows for vendor invoice register journals
    Accounts payable Vendor invoice workflow Use this type to create review workflows for vendor invoices
    Accounts payable Vendor redraw promissory note journal workflow Use this type to create approval workflows for vendor redraw promissory note journals
    Accounts payable Vendor settle promissory note journal workflow Use this type to create approval workflows for vendor settle promissory note journals
    Accounts receivable Customer bank remittance workflow Use this type to create approval workflows for customer bank remittance journals
    Accounts receivable Customer draw bill of exchange workflow Use this type to create approval workflows for customer draw bill of exchange journals
    Accounts receivable Customer free text invoice workflow Use this type to create approval workflows for free text invoices
    Accounts receivable Customer payment workflow Use this type to create approval workflows for customer payment journals
    Accounts receivable Customer protest bill of exchange workflow Use this type to create approval workflows for customer protest bill of exchange journals
    Accounts receivable Customer recurring invoice workflow Use this type to create approval workflows for recurring invoices
    Accounts receivable Customer redraw bill of exchange workflow Use this type to create approval workflows for customer redraw bill of exchange journals
    Accounts receivable Customer settle bill of exchange workflow Use this type to create approval workflows for customer settle bill of exchange journals
    Advanced ledger entry Advanced ledger entry workflow Use this type to create approval workflows for advance ledger entries
    Bank Bank reconciliation journal approval workflow Use this type to create approval workflows for Bank Reconciliation journals
    Budget plan Budget plan workflows Use this type to create and review workflows for budget plans
    Budget register entries Budget account entry workflow Use this type to create review workflows for budget account entries
    Budget register entries Budget register entry workflow Use this type to create review workflows for budget register entries
    Budget register entries Commitments approval Use this template to create approval workflows for commitment documents
    Case management Case management workflow Use this type to create a workflow for cases
    Case management Document handling Workflow type for document handling
    Fixed assets Ledger fixed assets budget journal workflow Use this type to create approval workflows for fixed asset budget journals
    Fixed assets Ledger post fixed assets journal workflow Use this type to create approval workflows for post fixed asset journals
    General ledger Ledger allocations journal workflow Use this type to create approval workflows for allocation journals
    General ledger Ledger daily journal workflow Use this type to create approval workflows for daily journals
    General ledger Ledger eliminations journal workflow Use this type to create approval workflows for eliminations journal
    Procurement and sourcing Catalog import approval Use this type to create review workflows for imported catalogs
    Procurement and sourcing Catalog import product approval Use this type to create review workflows for imported catalog products
    Procurement and sourcing Delivery due date notification workflow Use this type to create delivery due date notification workflows for unconfirmed product receipts
    Procurement and sourcing Invoice received notification workflow Use this type to create invoice received notification workflows for unconfirmed product receipts
    Procurement and sourcing Product receipt failed notification workflow Use this type to create notifications workflows for failed product receipts
    Procurement and sourcing Purchase order line workflow Use this type to create review- and approval workflows for purchase order lines
    Procurement and sourcing Purchase order workflow Use this type to create review- and approval workflows for purchase orders
    Procurement and sourcing Purchase requisition line review Use this type to create review workflows for purchase requisition lines
    Procurement and sourcing Purchase requisition review Use this type to create review workflows for purchase requisitions
    Procurement and sourcing Unconfirmed product receipt rejection notification workflow Use this type to create notification workflows for rejected unconfirmed product receipts
    Project Review budget revision workflow Use this type to review a budget revision
    Project Review original budget workflow Use this type to review an original budget
    Project Review project invoice proposals Use this type to review project invoice proposals
    Project Review project quotations Use this type to review project quotations
    Purchase agreement approval workflow Purchase agreement approval workflow Use this type to create approval workflows for purchase agreements
    Retail catalog workflow category Retail catalog approval workflow Retail catalog approval workflow type
    Signing limits Signing limits workflow Use this template to create a workflow for review of signing limit requests
    Time and attendance Time and attendance days total workflow Use this type to create approval workflows for time and attendance days total records
    Time and attendance Time and attendance journal registration workflow Use this type to create approval workflows for time and attendance journal registration records
    Timesheet Review timesheet line workflow Use this type to review a timesheet line
    Timesheet Review timesheet workflow Use this type to review a timesheet
    Travel and expense Cash advance request Use this type to create approval workflows for cash advance requests
    Travel and expense Dispute management Use this type to create workflows for credit card dispute management
    Travel and expense Expense line item Use this type to create line item approvals for expense reports
    Travel and expense Expense line item auto posting Use this type to create line item automatic posting workflows for expense reports
    Travel and expense Expense report Use this type to create document approvals for expense reports
    Travel and expense Expense report auto posting Use this type to create document automatic posting workflows for expense reports
    Travel and expense Travel requisition Use this type to create approval workflows for travel requisitions
    Travel and expense VAT tax recovery Use this type to create approval workflows for VAT tax recovery
    User management Inactivate user request workflow Use this type to create user inactivation workflows for inactivate user requests
    User management User request workflow Use this type to create user provisioning workflows for user requests
    Vendor request management Vendor add application workflow Use this type to create approval workflows for vendor add application requests
    Vendor request management Vendor add justification workflow Use this type to create approval workflows for vendor add justification requests
    Vendor request management Vendor category application workflow Use this type to create approval workflows for vendor category application requests
    Vendor request management Vendor category justification workflow Use this type to create approval workflows for vendor category justification requests
    Vendor request management Vendor status change request workflow Use this type to create approval workflows for vendor status change requests

    This list was exported using the following job:
    static void workFlowDescription(Args _args)
    {
    #AOT
    Treenode                workflowTypesNode, workFlowNode;
    int                     i;
    int                     nodeCount;
    str                     workflowName;
    SysDictWorkflowType     sysDictWorkflowType;
    SysDictWorkflowCategory sysDictWorkflowCategory;
    ;

    workflowTypesNode = treenode::findNode(#WorkflowTypesPath);
    nodeCount = workflowTypesNode.AOTchildNodeCount();

    workFlowNode = workflowTypesNode.AOTfirstChild();
    for (i=1; i<=nodeCount; ++i)
    {
    workflowName = workFlowNode.AOTgetProperty("Name");
    try
    {
    sysDictWorkflowType = SysDictWorkflowType::newTypeName(workflowName);
    sysDictWorkflowCategory = new SysDictWorkflowCategory(sysDictWorkflowType.category());
    info(sysDictWorkflowCategory.label() + ";"
    + sysDictWorkflowType.label() + ";"
    + sysDictWorkflowType.help());
    }
    catch ( Exception::Error)
    {
    exceptionTextFallThrough();
    }
    workFlowNode = workFlowNode.AOTnextSibling();
    }
    }


    Viewing all 53 articles
    Browse latest View live