Dynamics AX Blog - Beiträge von 2008 - Seite 4

Momentan angezeigt werden nur Beiträge von »2008«.

AX 2009 What's New Technical training - Technical

Diese Woche genoß ich einen eintägigen Ausflug in die neue Welt von Dynamics AX 2009 und lernte einige Aspekte der neuen Version aus technischer Sicht kennen. Anbei eine kurze Liste der für mich herausragensten Neuerungen:

  • Teilweise neue bzw. zumindest veränderte Oberfläche, sicherlich etwas gewöhnungsbedürftig
  • Grids sind scheinbar standard-mässig nach Excel exportierbar
  • Einführung der UTC-Timestamps, womit Zeitzonen-übergreifende Applikationen über einen AOS laufen können
  • Der Task-Rekorder ist scheinbar nun fixer Bestandteil von AX, wodurch zumindest rudimentäre Dokumentationen von Abläufen ermöglicht werden
  • Das neue Fill-Utility für Massenaktualisierungen
  • Erweiterung und Verbesserung im Umgang mit RecordSets
  • Erweiterung und Verbesserung im Umgang mit Queries (z.b. Union-Selects)
  • Einführung eines neuen, ax-basierenden Versionskontrollsystem namens MorphX VCS
  • Cross-Company-Support ermöglicht Formularen und Berichten mandantenübergreifend Daten anzuzeigen
  • Stapelverabeitung läuft komplett am AOS und wurde in einigen Belangen verbessert

Diese Liste ist weder vollständig noch wirklich validiert, hoffe in den nächsten Wochen etwas mehr Zeit mit der neuen Version verbringen zu dürfen :-)


 
 

Dynamics AX: SalesTable2LineField

In der Auftragserfassung gibt es im Auftragskopf Felder, die, wenn sie aktualisiert werden, entweder vollautomatisch bzw. nach Rückfrage beim Benutzer in den Auftragszeilen ebenfalls aktualisiert werden. Welche Felder das sind kann in den Debitorenparametern, Register Aktualisierungen über die Schaltfläche Auftragspositionen aktualisieren eingesehen werden. Dort kann auch parametriert werden, wie sich Dynamics AX bei der Aktualisierung dieser Felder verhalten soll.

Debitorenparameter - Auftragspositionen aktualisieren

Um nun ein weiteres Feld in diese Logik mitaufzunehmen bedarf es einiger Schritte. Im folgenden demonstriere ich die notwendigen Änderungen anhand des neuen Feldes DevReceiptDateRequested (abgeleitet vom EDT DevSalesReceiptDateRequested):

 

  • Neues Feld in Tabelle Salestable und Salesline anlegen
  • Das neue Feld in der Salestable in die Fieldgroup HeaderToLineUpdate integrieren
  • In der Klasse SalesTable2LineField die Methode lineUpdateDescription um das neue Feld erweitern (einfach die Logik eines bestehenden Feldes abschreiben)
  • In der Klasse SalesLineType die Methode initFromSalesTable um das neue Feld erweitern (einfach die Logik eines bestehenden Feldes abschreiben)
  • In der Klasse AxSalesline eine neue Methode wie folgt erstellen
    protected boolean isDevReceiptDateRequestedSet()
    {
         return this.isFieldSet(fieldNum(SalesLine, DevReceiptDateRequested)) ||
                this.AxSalesTable().isFieldModified(fieldNum(SalesTable, DevReceiptDateRequested));
    }
  • In der Klasse AxSalesline eine weitere Methode wie folgt erstellen
    public DevSalesReceiptDateRequested DevReceiptDateRequested(DevSalesReceiptDateRequested _DevReceiptDateRequested = dateNull())
    {
       if (!prmisdefault(_DevReceiptDateRequested))
       {
           this.setField(fieldNum(SalesLine, DevReceiptDateRequested), _DevReceiptDateRequested);
       }
     
       return SalesLine.DevReceiptDateRequested;
    }
  • In der Klasse AxSalesline eine dritte neue Methode wie folgt erstellen
    protected void setDevReceiptDateRequested()
    {
       if (this.isMethodExecuted(funcName(), fieldNum(SalesLine, DevReceiptDateRequested)))
       {
           return;
       }
       if (this.isDevReceiptDateRequestedSet())
       {
           this.DevReceiptDateRequested(this.AxSalesTable().DevReceiptDateRequested());
       }
    }
  • In der Klasse AxSalesLine muss nun die Methode setTableFields um den Aufruf der zuvor angelegten Methode setDevReceiptDateRequested erweitert werden
  • In der Klasse AxSalesTable eine neue Methode wie folgt anlegen
    protected void setDevReceiptDateRequested()
    {
        ;
        if (this.isMethodExecuted(funcName(), fieldNum(SalesTable, DevReceiptDateRequested)))
        {
            return;
        }
    }
  • In der Klasse AxSalesTable eine weitere Methode wie folgt anlegen
    public DevSalesReceiptDateRequested DevReceiptDateRequested(DevSalesReceiptDateRequested _DevReceiptDateRequested = dateNull())
    {
        ;
        if (!prmisdefault(_DevReceiptDateRequested))
        {
            this.setField(fieldNum(SalesTable, DevReceiptDateRequested), _DevReceiptDateRequested);
        }
    
        return salesTable.DevReceiptDateRequested;
    }
  • In der Klasse AxSalesTable muss nun die Methode setTableFields um den Aufruf der zuvor angelegten Methode setDevReceiptDateRequested erweitert werden
  • Nun muß noch folgender Code einmalig ausgeführt werden (z.B. per Job) um das neue Feld in die Aktualisierungslogik einzubinden
    SalesTable2LineParameters salesTable2LineParameters;
    ;
    ttsbegin;
    salesTable2LineParameters.clear();
    salesTable2LineParameters.initValue();
    salesTable2LineParameters.fieldId           = fieldNum(SalesTable, DevReceiptDateRequested);
    salesTable2LineParameters.table2LineUpdate  = Table2LineUpdate::Prompt;
    salesTable2LineParameters.insert();
    ttscommit;

Übrigens, die gleiche Logik gibt es natürlich auch einkaufsseitig. Die obige Abfolge und die Codebeispiele wurden unter AX3 entwickelt.

Update vom 28.07.2010: In Dynamics AX 2009 funktioniert die beschriebene Lösung genauso. Lediglich beim auszuführenden Job hat sich der Datentyp des Feldes table2LineUpdate geändert.


 
 

Dynamics AX: Methode des "Callers" aufrufen

Immer wieder besteht die Notwendigkeit, ein Formular über ein anderes zu öffnen und aus diesem heraus Methoden des Aufrufers aufzurufen.

Einfaches Beispiel: Ich öffne aus der Auftragsmaske (Salestable) irgendein anderes Formular (über einen MenuItemButton) und möchte nun beim Schliessen dieses Formulares eine Methode in der Salestable-Maske aufrufen.
Um dies zu realisieren muß ich einfach in der Close-Methode des Subformulars folgenden Code einbinden. myMethod steht dabei für die aufzurufende Methode des Salestable-Formulares.

Achtung: IntelliSense funtioniert in diesem Fall nicht (außer ich möchte eine Methode aufrufen, die im FormRun-Objekt enthalten ist).

if (element.args() && element.args().caller())
{
    if (element.args().caller().name() == formStr(Salestable))
    {
        element.args().caller().myMethod();
    }
}

 
 

Dynamics AX: FileIOPermission - Was ist das?

Die CodeAccessPermission-Klasse ist ein Mechanismus aus dem .NET-Framework, um den Zugriff von server-seitig ausgeführtem Quellcode auf geschützte Bereiche (z.b. einer Dateistruktur) vor bösartigen Attacken zu schützen.

Ob Code server- oder client-seitig ausgeführt wird, steuert bekanntermaßen das sogenannte RunOn-Property. Diese Eigenschaft ist z.b. beim Neuanlegen einer Klasse immer auf Called from eingestellt. D.h. wird diese Klasse über einen Menuitembutton aufgerufen läuft sie client-seitig, wird diese Klasse aber z.B. aus einem Stapellauf heraus aufgerufen, läuft sie am AOS.

 

Hat man also eine Klasse, die server-seitig laufen kann und bei der auf geschützte Bereiche zugegriffen wird, muß man eine der CodeAccessPermission-Klassen in seinen Programmcode einbinden.

Die bekannteste Klasse, die von der CodeAccessPermission abgeleitet ist, ist die FileIOPermission-Klasse, die für den Zugriff auf Dateien (über AsciiIo, TextIo, …) verwendet wird. Diese Klasse wird wie folgt verwendet:

FileIoPermission FileIoPermission;
AsciiIo          AsciiIo;
;
FileIoPermission = new FileIoPermission("c:\\File.txt",'w');
FileIoPermission.assert();

AsciiIo = new AsciiIo("c:\\File.txt",'w');
// ...

Muß man innerhalb einer Methode die assert-Methode mehrmals aufrufen, ist dies nur möglich wenn man zwischen den einzelnen Aufrufen CodeAccessPermission::revertAssert() einbindet.

FileIoPermission FileIoPermission;
AsciiIo          AsciiIo;
;
FileIoPermission = new FileIoPermission("c:\\File.txt",'w');
FileIoPermission.assert();

AsciiIo = new AsciiIo("c:\\File.txt",'w');
// ...

CodeAccessPermission::revertAssert()

FileIoPermission = new FileIoPermission("c:\\File_2.txt",'w');
FileIoPermission.assert();

AsciiIo = new AsciiIo("c:\\File_2.txt",'w');
// ...

Näheres zu den CodeAccessPermission-Klassen bzw. derer Kinder sind in der MSDN zu finden. 


 
 

Dynamics AX: Excel-Datei erstellen aus einer CSV-Datei

Manchmal ist es notwenig, aus Dynamics AX heraus per X++ eine "echte" Excel-Datei zu erstellen. Dazu stellt AX ja bekanntermaßen Objekte wie SysExcelApplication, SysExcelWorkBooks usw. zur Verfügung. Der Nachteil dieser Objekte ist rasch erwähnt: Sie sind langsam!

Aber es geht auch wesentlich rascher, allerdings mit dem Umweg per TextIO zuerst eine CSV-Datei zu erstellen und diese anschließend von AX in eine Excel-Datei umzuwandeln.

Der Code für letztere Umwandlung ist diesem Microsoft-Knowlegebase-Artikel zu entnehmen (erfordert PartnerSource-Zugriff).


 
 

Dynamics AX: SysMailerAddressField.appendAddress

In Dynamics AX 4.0 haben sich in der Klasse SysMailerAddressField in Methode appendAddress einige Fehler eingeschlichen. Diese Fehler treten immer dann auf, wenn man per SysMailer Mails an mehr als einen Empfänger versenden möchte bzw. zusätzlich zur Empfängeradresse auch Empfängernamen angibt.

Hier wird bisweilen das Mail entweder nur an die zuletzt hinzugefügte Mail-Adresse versandt oder aber die send-Methode des SysMailers verweigert ganz ihren Dienst, wenn man Empfängernamen angibt.

Nachstehend der - aus meiner Sicht - korrekte Code:

// Add item to the collection
void appendAddress(str addr, str name='')
{
    str address;
    str addresses;

    if (prmisdefault(name))
    {
        address = addr;
    }
    else
    {
        address = name + ' <' + addr + '>';
    }

    addresses = this.get();

    if (strlen(addresses) > 0)
    {
        address = addresses + ',' + address;
    }

    this.set(address);

    addressCount++;
}

 

Aufgefallen sind mir die Fehler bislang bei Version 4.0 bis inkl. SP2.


 
 

Dynamics AX: Report per Code aufrufen

Anbei ein Beispiel wie so mancher Report per Code ausgeführt werden kann, und dem Report dabei gleichzeitig ganz bestimmte Datensätze per Query übergeben werden können.

static void PrintCustCollectionLetterJour()
{
    CustCollectionLetterJour    CustCollectionLetterJour;
    query                       query;
    args                        args = new args();
    reportRun                   reportRun;
    ;

    select firstonly CustCollectionLetterJour;  // Irgendein Datensatz

    // Query aufbauen (mit obigen Datensatz)
    query = new query();
    query.addDataSource(tableNum(CustCollectionLetterJour));

    SysQuery::findOrCreateRange(query.dataSourceTable(TableNum(CustCollectionLetterJour)),
        fieldNum(CustCollectionLetterJour, CollectionLetterNum)).value(CustCollectionLetterJour.CollectionLetterNum);
    SysQuery::findOrCreateRange(query.dataSourceTable(TableNum(CustCollectionLetterJour)),
        fieldNum(CustCollectionLetterJour, AccountNum)).value(CustCollectionLetterJour.AccountNum);

    // Den Query dem Report übergeben
    args.name(reportstr('CustCollectionJour'));

    reportRun = classFactory.reportRunClass(args);

    reportRun.query().interactive(false);
    reportRun.report().interactive(false);
    reportRun.query(query);

    reportRun.init();

    reportRun.run();
}

 
 
Seiten « 1 2 3 4 5 6 » 

 

 
 
 
Beiträge des aktuellen Monats
April 2008
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