Dynamics AX Blog - Axapta 3.0 - Seite 5

Momentan angezeigt werden nur Beiträge, welche für die Dynamics AX-Version »Axapta 3.0« relevant sind. Filter entfernen

RSS-Feed dieser Version

Dynamics AX: Notizen zu Labelfiles

Es gibt vier verschiedene Dateien, in welchen serverseitig Informationen zu Labels gespeichert werden:

Datei-erweiterung Beschreibung
*.ald Axapta Application Label Data
  Kann per Editor bearbeitet werden (z.b. Notepad). Ist gleichzeitig auch die einzige Datei, die man selbst bearbeiten kann/soll
*.alc Axapta Application Label Comments
  Axapta Application Label Comments
*.ali Axapta Application Label Index
  Diese Dateien können eigentlich jederzeit gelöscht werden, sie werden zu verschiedenen Zeitpunkten automatisch neu generiert (z.B. wenn der Client gestartet wird, wird zumindest jenes Index-File in der gerade verwendeten Sprache erstellt; Wenn man im Labeleditor nach einem Label sucht, werden die Index-Files aller Sprachen neu aufgebaut)
*.alt Axapta Application Label Temp Store
  Hier werden Labels temporär gespeichert, wenn ein Entwickler welche anlegt Erst bei Beenden des Clients bzw. des AOS werden diese neuen Label ins ald-File übertragem (dazu wird übrigens kurzfristig ein alb-file generiert)

 

Bei den Datetypen, ald, alc und ali existiert pro Sprache und Labelfile jeweils eine Datei im AX-Applikationsverzeichnis (z.b. axSYSde-at wobei SYS für die Labeldatei und de-at für die jeweilige Sprache steht).

Bei den alt-Dateien existiert lediglich pro Sprache eine eigene Datei (z.b. axap*.alt wobei * für die jeweilige Sprache steht).

Einige Labels werden allerdings clientseitig im bin-Verzeichnis gespeichert. Dies sind z.b. jene des Menüs (Datei - Bearbeiten - Werkzeuge ...). Hier gibt es eigene Dateitypen:

Datei-erweiterung Beschreibung
*.ktd Axapta Application Kernel Translation Data
  Kann per Editor bearbeitet werden (z.b. Notepad). Ist gleichzeitig auch die einzige Datei, die man selbst bearbeiten kann/soll
*.kti Axapta Application Kernel Translation Index

Bei beiden Dateitypen existiert pro verwendeter Sprache jeweils eine Datei.

Da die Dateien clientseitig installiert sind, kann rein theoretisch jeder Client zumindest diese Texte anpassen, ob das Sinn macht bleibt dahingestellt. Außerdem besteht die Gefahr die Datei, durch Tippfehler oder wenn man die ktd-Datei im falschen Zeichensatz bearbeitet, zu zerstören. Dann ist der Client nicht mehr startbar!

In dieser ktd-datei werden übrigens auch einige andere Dinge gesteuert. Zum Beispiel liefert in einem deutschen AX die Abfrage

if("a" == "ä")

immmer true zurück. Grund hierfür ist die nachstehende Passage im zur deutschen Sprache gehörigen axsysde-at.ktd

>#97
>TC_COLSEQ
>Definition of collating sequence mapping
>This table is used when sorting letters and strings
>First line is the letters to be mapped
>Second line is the corresponding letter to map to
AàáâãäÀÁÂÃÄBCçÇDEèéêëÈÉÊËFGHIìíîïÌÍÎÏJKLMNñÑOòóôõöÒÓÔÕÖPQRSTUùúûüÙÚÛÜVWXYýÝZæøåÆØÅ
aaaaaaaaaaabcccdeeeeeeeeefghiiiiiiiiijklmnnnooooooooooopqrstuuuuuuuuuvwxyyyz~¦Ç~¦Ç

 


 
 

Dynamics AX: Rechnungen per Code drucken

Über nachstehenden Code kann ganz einfach jederzeit eine Verkaufsrechnung nachträglich ausgedruckt werden. Durch leichte Modifikationen des Codes gilt dies auch für sämtliche anderen verkaufs- und einkaufsseitigen Dokumente.

Hier ein kurzes Beispiel unter AX 2009

static void PrintSalesInvoice(Args _args)
{
   custInvoiceJour     custInvoiceJour;
   SalesFormLetter     salesFormLetter = SalesFormLetter::construct(DocumentStatus::Invoice, false);
   PrintJobSettings    printJobSettings = new PrintJobSettings();
   Args                args = new Args();
   boolean             prompt = true;
   boolean             printIt = true;
   ;

   if (prompt)
   {
       // Auswahl des Benutzers über Dialog
       printIt = printJobSettings.printerSettings('SysPrintForm');
   }
   else
   {
       // Printjobsettings per Code steuern
       printJobSettings.setTarget(PrintMedium::File);
       printJobSettings.format(PrintFormat::PDF);
       printJobSettings.fileName(@'c:\temp\myfile.pdf');
   }

   if (!printIt)
   {
       return; // Benutzerabbruch
   }

   salesFormLetter.updatePrinterSettingsFormLetter(printJobSettings.packPrintJobSettings());

   select firstOnly custInvoiceJour
       where custInvoiceJour.salesid == '100001';

   args.record(custInvoiceJour);
   args.caller(salesFormLetter);

   new MenuFunction(menuitemoutputstr(SalesInvoice), MenuItemType::Output).run(args);
}

Nachstehend ein Code-Beispiel unter AX 4.0

static void PrintSalesInvoice(Args _args)
{
   custInvoiceJour     custInvoiceJour;
   SalesFormLetter     salesFormLetter = SalesFormLetter::construct(DocumentStatus::Invoice, false);
   PrintJobSettings    printJobSettings = new PrintJobSettings();
   Args                args = new Args();
   boolean             prompt = true;
   boolean             printIt = true;
   salesPrintSetup     salesPrintSetup;
   ;

   if (prompt)
   {
       // Auswahl des Benutzers über Dialog
       printJobSettings = new PrintJobSettings(salesPrintSetup.PrintJobSettings);
       printIt = printJobSettings.printerSettings('SysPrintForm');
       salesPrintSetup.PrintJobSettings = printJobSettings.packPrintJobSettings();
   }
   else
   {
       // Printjobsettings per Code steuern
       printJobSettings.setTarget(PrintMedium::File);
       printJobSettings.format(PrintFormat::PDF);
       printJobSettings.fileName(@'c:\temp\myfile.pdf');
   }

   if (!printIt)
   {
       return; // Benutzerabbruch
   }

   salesFormLetter.updatePrinterSettingsFormLetter(printJobSettings.packPrintJobSettings());

   select firstOnly custInvoiceJour
       where custInvoiceJour.salesid == '100001';

   args.record(custInvoiceJour);
   args.caller(salesFormLetter);

   new MenuFunction(menuitemoutputstr(SalesInvoice), MenuItemType::Output).run(args);
}

 
 

Vor- und rückwärts kompilieren in AX

Heute musste ich eine AX-Standard-Klasse adaptieren und nach meiner Adaption wurde ich mit merkwürdigen Fehlermeldungen dieser Klasse konfrontiert, die aber allesamt mit meiner Änderung nicht direkt etwas zu tun hatten (Bsp: "Elemententyp kann nicht zugewiesen werden").

Kompilieren, aus- und einsteigen, neustarten des AOS, all das half nichts gegen diese Fehlermeldungen. Erst als ich alle Klassen mitkompiliert habe, die von meiner "Problemklasse" abgeleitet waren, waren die Fehlermeldungen verschwunden. Objektorientierte Programmierung kann auch so seine Fallen haben ;-)

Sämtliche Eltern und Kinder eines Objekts findet Ihr in AX übrigens im Kontext-Menü unter AddIns / Entwicklungshierachie. In dieser Maske kann man u.a. vor- und rückwärts kompilieren.

Entwicklungshierachie

Zusätzlich dazu sieht man in der Übersicht, welche Methoden in welcher dieser Klassen verwendet werden, in welchen Schichten (Layer) das Objekt existiert und bei aktualisierten Querverweisen auch die Anzahl derselben.


 
 

AxInventTable: Artikel per Code anlegen

Sowohl unter AX3 als auch AX4 gibt es die Klasse AxInventTable, mit der sich ganz einfach per Code Artikel anlegen lassen. Leider ist die Klasse in der 3er-Version noch nicht ganz so programmiererfreundlich, deshalb also anbei zwei Code-Beispiele wie diese Klasse in den beiden AX-Version genutzt werden kann.

Artikel per Code anlegen unter AX4...

static void CreateItemAX4(Args _args)
{
    axInventTable   axInventTable;
    ;
    
    axInventTable = new axInventTable();

    // Pflichtfeldverprüfung aktivieren
    axInventTable.validateInput(true);  

    // Werte setzen
    axInventTable.parmItemId        ('DL-100-D4');
    axInventTable.parmItemName      ('Deckenlampe - Silber');
    axInventTable.parmItemGroupId   ('Lampen');
    axInventTable.parmModelGroupId  ('DEF');
    axInventTable.parmDimGroupId    ('Std-Dim');

    // Datensatz speichern
    axInventTable.save();
} 

...und AX3

static void CreateItemAX3(Args _args)
{
    axInventTable   axInventTable;
    sysDictTable    sysDictTable = new sysDictTable(tableNum(InventTable));
    int             field;
    boolean         validateField = false;
    ;

    axInventTable = new axInventTable();

    // Werte setzen
    axInventTable.itemId        ('DL-100-D3');
    axInventTable.ItemName      ('Deckenlampe - Silber');
    axInventTable.ItemGroupId   ('Lampen');
    axInventTable.ModelGroupId  ('DEF');
    axInventTable.DimGroupId    ('Std-Dim');

    // Prüfung der einzelnen Felder
    for(field = 1; field <= sysDictTable.fieldCnt(); field++)
    {
        validateField = axInventTable.inventTable().validateField(field);
    }

    // Datensatz speichern
    if(axInventTable.inventTable().validateWrite() && validateField)
    {
        axInventTable.save();
    }
}

 
 

Stolpersteine beim Exportieren von AX4 --> AX3

Wenn man Objekte aus einer AX4-Umgebung in eine AX3-Umgebung importieren will, muss man selbstverständlich darauf achten, daß der zu importierende Code auch von AX3 verstanden wird. Aber selbst wenn dies sichergestellt ist, muß man im XPO selbst einige Anpassungen vornehmen, um die Objekte überhaupt einspielen zu können. Einige derartiger "Stolpersteine" findet Ihr im folgenden:

 

Im Export-File der Version 4 müssen folgende Textpassagen rausgelöscht werden:

<Table:Field name="recVersion">0</Table:Field>

und

<Table:Field name="SysLabelApplModule">0</Table:Field>

Letzterer Text ist im XPO nur dann vorhanden, wenn man Labels mit exportiert hat.

 

Des weiteren muß, soferne man Menus transferieren will, der Text

MNUVERSION 4

durch

MNUVERSION 3

ersetzt werden.

 

Danach mus das gesamte XPO im ANSI-Format gespeichert werden, mit Hilfe von z.b. Notepad und dessen "Speichern unter..."-Dialog sollte dies aber kein Problem sein.

Ausserdem ist mir noch aufgefallen, daß AX3 scheinbar die Eigenschaft Columns in einem Design einer Form nicht importieren kann. Diese Eigenschaft wird nach einem Import standardmässig auf 2 gesetzt. Um sich durch dieses Verhalten keine Probleme einzuhandeln, sollte man schon beim Gestalten eines Formulares darauf achten, diese Eigenschaft immer auf 2 zu setzten.

Nachtrag vom 19. März 2008

Müssen MenuItems transferiert werden, so muß außerdem

ObjectType

durch

Class

ersetzt werden.


 
 

Fehlermeldungen in AX aussagekräftiger gestalten

Info, warning und error sind das täglich Brot des AX-Entwicklers. Schließlich kann er über diese Befehle dem Benutzer mitteilen, was er getan hat, zu tun hat oder nicht hätte tun sollen. Und dies erfolgt in der Regel mit einer mehr oder weniger aussagekräftigen Fehlermeldung. Unterstützen kann man diese auf einfache Art und Weise mit dem zusätzlichen Parameter sysInfoAction. Anbei einige Beispiele, wie man diesen einsetzen kann:

static void InfoWarningErrorExamples(Args _args)
{
    query query;
    CustTable CustTable;
    sysInfoAction_MenuFunction sysInfoAction_MenuFunction;
    ;

    // Öffnet ein Formular mit einer Auswahl an Datensätzen (über eine Query)
    // Zusätzlich kann man hier ein FormControl angeben, welches nach dem öffnen den Fokus erhält
    query = new query();
    query.addDataSource(tableNum(CustTable)).addRange(fieldNum(CustTable, AccountNum)).value('401*');
    info(   'Bitte überprüfen Sie, ob bei allen betroffenen Debitoren die selbe Debitorengruppe eingetragen ist',
             'APPLDOC://Tables/CustTable/CustGroup',
             sysInfoAction_FormRunQuery::newFormnameControlnameQuery(formStr(CustTable),'Posting_CustGroup', query));

    // Öffnet nur das Formular ohne einen bestimmten Datensatz auszuwählen, man kann aber den Names
    // eines FormControl angeben, welches den Fokus zu öffnenden Formular erhalten soll
    warning(   'Bitte überprüfen Sie die Einstellungen der am Debitoren hinterlegten Debitorengruppe',
                'APPLDOC://Tables/CustTable/CustGroup',
                sysInfoAction_FormRun::newFormnameControlnameDesc(  formStr(CustTable),
                                                                    'Posting_CustGroup'
                                                                    'Debitorengruppe anzeigen'));

    // Öffnet das Formular mit einem bestimmten Datensatz und setzt den Fokus auf ein bestimmtes Feld
    CustTable = CustTable::find('4011');
    error(  'Bitte überprüfen Sie die Einstellungen der am Debitoren hinterlegten Debitorengruppe',
            'APPLDOC://Tables/CustTable/CustGroup',
            sysInfoAction_TableField::newBufferField(CustTable, fieldNum(CustTable, custGroup)));


    // Öffnet ein Formular über die Angabe des entsprechenden MenuItems
    // Dabei kann ein Datensatz ausgewählt werden, welcher angezeigt werden soll
    // ACHTUNG: Funktioniert nicht bei allen Formularen (Tabellenrelationen werden benötigt)
    sysInfoAction_MenuFunction = new sysInfoAction_MenuFunction();
    sysInfoAction_MenuFunction.parmDataAreaId(curext());
    sysInfoAction_MenuFunction.parmMenuItemType(MenuItemType::Display);
    sysInfoAction_MenuFunction.parmMenuItemName(identifierStr(CustTable));
    sysInfoAction_MenuFunction.parmCallerBuffer(CustTable::find('4011'));

    info('Bitte überprüfen Sie die Stammdaten des Debitoren', '', sysInfoAction_MenuFunction);
}

Nachstehend die äquivalenten Befehle in AX 3.0.

static void InfoWarningErrorExamples(Args _args)
{
    query query;
    CustTable CustTable;

    sysInfoAction_FormRunQuery sysInfoAction_FormRunQuery;
    sysInfoAction_FormRun sysInfoAction_FormRun;
    sysInfoAction_TableField sysInfoAction_TableField;
    ;

    // Öffnet ein Formular mit einer Auswahl an Datensätzen (über eine Query)
    // Zusätzlich kann man hier ein FormControl angeben, welches nach dem öffnen den Fokus erhält
    query = new query();
    query.addDataSource(tableNum(CustTable)).addRange(fieldNum(CustTable, AccountNum)).value('401*');
    sysInfoAction_FormRunQuery = new sysInfoAction_FormRunQuery(formStr(CustTable),'Posting_CustGroup', query);
    info(   'Bitte überprüfen Sie, ob bei allen betroffenen Debitoren die selbe Debitorengruppe eingetragen ist',
             'APPLDOC://Tables/CustTable/CustGroup',
             sysInfoAction_FormRunQuery);

    // Öffnet nur das Formular ohne einen bestimmten Datensatz auszuwählen, man kann aber den Names
    // eines FormControl angeben, welches den Fokus zu öffnenden Formular erhalten soll
    sysInfoAction_FormRun = new sysInfoAction_FormRun(formStr(CustTable),
                                                      'Posting_CustGroup',
                                                      'Debitorengruppe anzeigen');
    warning(   'Bitte überprüfen Sie die Einstellungen der am Debitoren hinterlegten Debitorengruppe',
                'APPLDOC://Tables/CustTable/CustGroup',
                sysInfoAction_FormRun);

    // Öffnet das Formular mit einem bestimmten Datensatz und setzt den Fokus auf ein bestimmtes Feld
    CustTable = CustTable::find('4011');
    sysInfoAction_TableField = new sysInfoAction_TableField(CustTable, fieldNum(CustTable, custGroup));
    error(  'Bitte überprüfen Sie die Einstellungen der am Debitoren hinterlegten Debitorengruppe',
            'APPLDOC://Tables/CustTable/CustGroup',
            sysInfoAction_TableField);
}

Aussehen tun solche Fehlermeldungen dann zum Beispiel wie folgt


 
 

GoToMainTable mal anders

Die "Gehe zum Haupttabellenformular"-Funktion in AX ist ja was feines. Abhängig von Datenbank-Relationen kümmert sich im Normalfall AX vollkommen autark um diese Funktion. Und wenn einmal keine Relationen zur Verfügung stehen sollten, kann man durch Überschreiben der Methode jumpRef mit nachstehenden Code auf beinahe jedem Eingabe-Feld unter Angabe der Tabelle und des betroffenen Tabellenfeldes - im Beispiel die Debitorengruppe, AX dazu bewegen, das entsprechende Formular zu öffnen.

 

public void jumpRef()
{
    sysDictField sysDictField;
    menufunction menufunction;
    ;

    sysDictField = new sysDictField(tableNum(CustTable), fieldNum(CustTable, CustGroup));

    menufunction = sysDictField.gotoMainTableMenuFunction();
    if(menufunction)
        menufunction.run();
}

Funktioniert in AX 3.0 und 4.0. Das obige Code-Schnippsel öffnet wirklich einfach nur das Formular, einen bestimmten Datensatz innerhalb desselben (z.B. abhängig vom bereits eingetragenen Wert im Eingabe-Feld), kann man damit nicht vorselektieren.

Übrigens, in dem Zusammenhang: Manchmal macht es Sinn, diese Funktion zu deaktivieren. Dazu kann man entweder das super() aus der Methode context entfernen, dann fehlt dem betroffenen Feld aber das komplette Kontext-Menü.

public void context()
{
    //super();
}

Zumindest etwas eleganter ist es, das super() aus der Methode jumpRef zu entfernen, dann ist zwar der Menüpunkt im Kontext-Menü nach wie vor vorhanden, aber ohne Funktion.

public void jumpRef()
{
    //super();
}

 
 
Seiten « 1 2 3 4 5 6 » 

 

 
 
 
Beiträge des aktuellen Monats
Dezember 2021
MoDiMiDoFrSaSo
 12345
6789101112
13141516171819
20212223242526
2728293031 
 
© 2006-2021 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