Dynamics AX Blog - Microsoft Dynamics AX (Axapta) - Seite 35

Momentan angezeigt werden nur Beiträge der Kategorie »Microsoft Dynamics AX (Axapta)« Filter entfernen

In den letzten Jahren, in denen ich mich fast hauptsächlich mit der Entwicklung im Umfeld von Microsoft Dynamics AX (vormals Axapta) beschäftigt habe, ist das eine oder andere Code-Fragment entstanden, von dem ich mir vorstellen könnte, daß es auch für andere AX-Entwickler ganz nützlich sein könnte. Aber auch Tips und Tricks zu dem mächtigen ERP-System werde ich in dieser Kategorie präsentieren.

RSS-Feed dieser Kategorie

Projekte nach einem bestimmten Objekt durchsuchen

Nachstehender Job durchsucht alle Projekte nach einem bestimmten Element des AOT.

Dafür wird ein Dialog verwendet, wo man lediglich den Namen und den Typ des zu suchenden Elementes angeben muss. Außerdem kann man noch einstellen, ob auch die privaten Projektknoten durchsucht werden sollen.

static void findObjectWithinProjects(Args _args)
{
    UtilElementType utilElementType        = UtilElementType::Table;
    Name            objectName             = 'custTable';
    boolean         includePrivateProjects = false;
    Dialog          dialog;
    DialogField     df_objectName;
    DialogField     df_utilElementType;
    DialogField     df_privateProjects;
    container       conProjects;
    int             c;
    TreeNode                treeNodeRoot;
    SysOperationProgress    sysOperationProgress;
    UtilElementType         utilElementTypeSelection;    

    #Aot
    #TreeNodeSysNodeType
    #AviFiles
    #define.objectNameField("Name of object")
    #define.utilElementTypeField("Type of object")

    void findChildNodes(TreeNode _treeNodeParent, ProjectNode _projectNode, str _objectName)
    {
        TreeNode            treeNode;
        TreeNodeIterator    treeNodeIterator;

        ; 
        treeNodeIterator = _treeNodeParent.AOTiterator();
        treeNode = treeNodeIterator.next();
        while (treeNode)
        {
            if (treeNode.AOTgetNodeType() == #NT_PROJECT_GROUP)
            {
                findChildNodes(treeNode, _projectNode, _objectName);
            }
            else if (treeNode.AOTname() like _objectName)
            {
                utilElementTypeSelection = str2enum(utilElementTypeSelection, enum2str(utilElementType)); 
                if (!utilElementType || treeNode.applObjectType() == utilElementTypeSelection)
                {
                    if (!confind(conProjects, _projectNode.AOTname()))
                    {
                        conProjects = conins(conProjects, conlen(conProjects)+1, _projectNode.AOTname());
                    } 
                    return;
                }
            } 
            treeNode.treeNodeRelease();
            treeNode = treeNodeIterator.next();
        }
    }
    void loopProjectsNode(TreeNode _treeNode)
    {
        ProjectNode projectNode;
        TreeNode treeNodeProject; 

        if (_treeNode)
        {
            treeNodeProject = _treeNode.AOTfirstChild();
            while (treeNodeProject)
            {
                projectNode = treeNodeProject; 
                sysOperationProgress.setText(projectNode.name()); 
                findChildNodes(projectNode.loadForInspection(), treeNodeProject, objectName); 
                treeNodeProject = treeNodeProject.AOTnextSibling();
            }
        }
    }
    ; 
    dialog = new Dialog();
    dialog.caption("Find projects containing specific object");
    df_objectName      = dialog.addField(Types::String, #objectNameField);
    df_utilElementType = dialog.addField(typeid(UtilElementType), #utilElementTypeField);
    df_privateProjects = dialog.addField(typeid(NoYesId), "Include Private projects"); 
    df_objectName.value(objectName);
    df_utilElementType.value(utilElementType);
    df_privateProjects.value(includePrivateProjects); 
    if( !dialog.run())
    {
        return;
    } 
    objectName             = df_objectName.value();
    utilElementType        = df_utilElementType.value();
    includePrivateProjects = df_privateProjects.value(); 
    if (objectName == '*' || objectName == '')
    {
        throw error(strfmt("@SYS26332", #objectNameField));
    } 
    setprefix(strfmt("Projects containing %1 '%2'", utilElementType, objectName)); 

    startLengthyOperation(); 

    sysOperationProgress = new SysOperationProgress();
    sysOperationProgress.setCaption("Searching");
    sysOperationProgress.setAnimation(#AviSearch); 

    // Private projects
    if(includePrivateProjects)
    {
        loopProjectsNode(SysTreeNode::getPrivateProject());
    }
    // Shared projects
    loopProjectsNode(SysTreeNode::getSharedProject()); 
    sysOperationProgress.kill();
    endLengthyOperation(); 

    // List projects
    for(c=1;c<=conlen(conProjects);c++)
    {
        info(conpeek(conProjects, c));
    }
}

Wer eine etwas komfortablere Möglichkeit vorzieht, der kann sich bei Firma Loncar Technologies Inc. ein entsprechendes XPO herunterladen und ins AX einspielen. Auf Basis dieses XPOs ist auch obiger Job entstanden.

https://www.loncartechnologies.com/download.php


 
 

Berechtigung eines Benutzers für einen Sicherheitsschlüssel abfragen

Mit diesem Stückchen Code kann man in Dynamics AX prüfen, welche Berechtigung ein Benutzer für einen bestimmten Sicherheitsschlüssel (Securitykey) hat.

static void GetSecurityKeyAccess4User(Args _args)
{
    Dictionary          Dictionary = new Dictionary();
    securityKeyId       securityKeyId;
    SecurityKeySet      securityKeySet = new SecurityKeySet();
    UserId              userId = 'user1';
    SelectableDataArea  dataArea = 'ceu';
    AccessType          accessType;
    ;

    securityKeyId = Dictionary.securityKeyName2Id("BatchReport");

    securityKeySet.loadUserRights(userId, dataArea);

    AccessType = securityKeySet.access(securityKeyId);

    info(enum2str(AccessType));
}

 
 

AX 2012: Having-Clause über addHavingFilter

Ein neues Feature von Dynamics AX 2012 ist, daß man nun bei einem Query auch eine HAVING-Clause hinzufügen kann.

Diese Bedingung dient dazu, berechnete Werte einer GROUP BY-Clause in der WHERE-Clause berücksichtigen zu können. Dieses Feature habe ich in der Vergangenheit vor allem dazu gerne verwendet, wenn es darum ging über eine SQL-Abfrage doppelte (bzw. vielfache) Datensätze in einer Tabelle zu finden. In den bisherigen Versionen von Dynamics AX war dieses Unterfangen über X++ nur etwas umständlich abzubilden.


 
 

AX 2012: AddQueryFilter

In Dynamics AX 2012 verfügt das Query-Objekt nun über eine neue Methode addQueryFilter, mit dessen Hilfe man die Datenbank anweisen kann, Filterkriterien zur WHERE-Clause statt wie in bisherigen Versionen zur ON-Clause einer OUTER-JOIN-Verknüpfung hinzuzufügen. Dies wiederum bewirkt, daß keine "leeren" Datensätze verarbeitet werden.


 
 

AX 2012: ValidTimeState

Wer schon einmal eine Tabelle aufbauen musste, wo die einzelnen Datensätze über Datumsfelder nur für einen bestimmten Zeitraum gültig sind - ähnlich den Handelsvereinbarungen -, weiß wieviel Entwicklungsaufwand daintersteckt, wenn sichergestellt werden muss, daß sich die Gültigkeitsbereiche der einzelnen Datensätze nicht überschneiden.

Dynamics AX 2012 stellt hierfür eine neue Tabelleneigenschaft validTimeStateFieldType zur Verfügung, mit deren Hilfe sich Dynamics AX selbst um vieles kümmert.

Beim Anlegen einer solchen Tabelle muss nur auf die folgenden Punkte geachtet werden:

  1. Eigenschaft ValidTimeStateFieldType der Tabelle auf Date oder UtcDateTime setzen. Dadurch erstellt AX zwei neue Felder ValidFrom und ValidTo in der Tabelle.


     
  2. Man muss einen eindeutigen Index erstellen, der die entscheidenden Felder der Tabelle sowie die Felder ValidFrom und ValidTo enthält.


     
  3. Bei diesem Index müssen bestimmte Eigenschaften gesetzt werden.

 

Ab diesem Zeitpunkt kümmert sich Dynamics AX vollständig um das Aktualisieren von nicht mehr gültigen Datensätzen und die entscheidenden Prüfungen beim Anlegen von neuen Datensätzen.

Aber auch das Selektieren des jeweils gültigen Datensatzes für ein bestimmtes Datum wird wesentlich erleichert. Dafür stellt Dynamics AX das Keyword validTimeState zur Verfügung.

static void AX2012_ValidTimeStateUtcDateTime(Args _args)
{
    AX2012_ValidTimeStateUtcDateTime AX2012_ValidTimeStateUtcDateTime;
    utcDateTime myUtcDateTime = 1988-07-20T13:34:45;
    ;
    select validTimeState(myUtcDateTime) *
    from AX2012_ValidTimeStateUtcDateTime;

    info(strFmt("%1", AX2012_ValidTimeStateUtcDateTime.salesPrice));
}

 


 
 

Notizen zu Systemdatum und -zeit

Im folgenden sind einige Gedankennotizen zum Thema Datum und Uhrzeit in Dynamics AX notiert.

In allen mir bekannten Versionen von Dynamics AX bzw. Axapta gibt es die nachstehenden Funktionen:

Funktionsaufruf Beschreibung
today() Datum des Clients
systemDateGet() Sitzungsdatum von AX
timeNow() Zeit des Clients

Ab Dynamics AX 2009 stehen u.a. zusätzliche folgende Funktionen zur Verfügung: 

Funktionsaufruf Beschreibung
DateTimeUtil::getSystemDateTime() Sitzungsdatum/-zeit von AX in koordinierter Weltzeit 
DateTimeUtil::applyTimeZoneOffset
(
    DateTimeUtil::getSystemDateTime(),
    DateTimeUtil::getUserPreferredTimeZone()
)
Sitzungsdatum/-zeit von AX für die aktuelle Zeitzone des Benutzers
 DateTimeUtil::date(_utcDateTime) Wandelt einen UTC-Datetime-Wert in ein Datum um

In allen bisherigen Dynamics AX-Versionen wird das Systemdatum und die Systemzeit von der Zeit des Clients initialisiert. Diese Werte kann sich der Benutzer - entsprechende Rechte vorausgesetzt - jederzeit selbst ändern (die Uhrzeit allerdings erst seit Dynamics AX 2009). Sie gelten aber nur für die aktuelle Sitzung und nur für diesen Benutzer.
 
Übrigens: Erhält man unter AX 2009 beim Starten eines AX-Clients die nachstehende Fehlermeldung, sollte man die Zeitzone des aktuellen Benutzers in den Benutzeroptionen prüfen.

Die Zeitzone des lokalen Comuters stimmt nicht mit den Einstellungen für die bevorzugte Zeitzone überein.

 


 
 

Druckeinstellungen und Filterkriterien eines Reports vorbelegen II

Wie startet man einen Bericht, bei dem eine von RunBaseReport abgeleitete Klasse vorgeschalten ist, per X++ und gibt diesem Bericht bereits den Query und die Druckeinstellungen vor?

Wer sich diese Frage schon einmal stellen musste, für den liefert dieser Blogbeitrag vielleicht einen Lösungsansatz:

static void setPrintJobSettingsQuery4ReportClass_II(Args _args)
{
    custReport          custReport = new custReport();
    printJobSettings    printJobSettings = new printJobSettings();
    ;
    custReport.makeReportRun();

    // Modify Query
    sysQuery::findOrCreateRange(custReport.reportRun().query().dataSourceTable(tableNum(custTable)), fieldNum(custTable, custGroup)).value(queryValue('10'));
    custReport.reportRun().query().interactive(false);
    // Create printJobSettings
    printJobSettings.setTarget(PrintMedium::File);
    printJobSettings.format(PrintFormat::PDF);
    printJobSettings.fileName(@"C:\Temp\CustTableReport.pdf");

    // Apply printJobSettings
    custReport.reportRun().printJobSettings(printJobsettings.packPrintJobSettings());
    custReport.reportRun().report().interactive(false);  // Disable default printer-dialog
    custReport.reportRun().run();
}

Obiger Code instanziiert ein Objekt der Klasse custReport, deren wesentliche Methoden wie folgt aussehen:

class CustReport extends runBaseReport
{
}

 

public identifiername lastValueElementName()
{
    identifiername ret;

    //ret = super();

    ret = reportStr(Cust);

    return ret;
}

 

static ClassDescription description()
{
    return "Custreport";
}

 

static void main(Args args)
{
    CustReport  CustReport;
    ;
    CustReport = new CustReport();
    if (CustReport.prompt())
    {
        CustReport.run();
    }
}

 
 
Seiten « 1 ... 32 33 34 35 36 37 38 ... 52 » 

 

 
 
 
Beiträge des aktuellen Monats
April 2025
MoDiMiDoFrSaSo
 123456
78910111213
14151617181920
21222324252627
282930 
 
© 2006-2025 Heinz Schweda | Impressum | Kontakt | English version | Mobile Version
Diese Webseite verwendet Cookies, um Benutzern einen besseren Service anzubieten. Wenn Sie weiterhin auf der Seite bleiben, stimmen Sie der Verwendung von Cookies zu.  Mehr dazu