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

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 KategoriePageFooter sind nicht immer dort, wo sie sein sollten
04.12.2009Microsoft Dynamics AX (Axapta)
Ich kenne kein einziges AX-Projekt, in dem nicht zumindest einer der Berichte Auftragsbestätigung, Ausgangslieferschein oder Ausgangsrechnung angepasst worden sind. Und deshalb stolpere ich auch immer wieder über das selbe Problem: Man erweitert einen Bericht (Report) um einen PageFooter, der aber nicht auf jeder Seite angedruckt werden soll. |
Vorsicht beim Mandanten duplizierenDaß man einen Mandanten/Unternehmen duplizieren kann, ist bekannt. Die Erfahrung der vergangenen Wochen hat mich in dem Zusammenhang folgendes gelehrt:
Um sicherzustellen, daß man der einzige Benutzer im System ist, sollte man alle anderen deaktivieren. Außerdem sollte man vor dem Kopiervorgang ein Datenbank-Backup anlegen und nach der erfolgten Aktion den Quell- und Zielmandant hinsichltich doppelter Datensätze vergleichen. Hierfür kann man sich der Funktion "Anzahl der Datensätze" bedienen. |
Alle Felder einer Tabelle auflisten
22.11.2009Microsoft Dynamics AX (Axapta)
Kurzes Codebeispiel, wie man alle Felder einer Tabelle auflistet: static void ListFieldOfTable(Args _args)
{ dictTable dictTable; int currFieldId = 0; counter c = 0; ; dictTable = new dictTable(tableNum(custtable)); do { currFieldId = dictTable.fieldNext(currFieldId); info(dictTable.fieldName(currFieldId)); c++; } while (c < dictTable.fieldCnt()); }
|
Arbeiten mit dem aufrufenden Objekt einer Form (Caller)Nachstehende Methode enthält einige Snippets, die in einem Formular verwendet werden können, um in Dynamics AX diverse Funktionen/Methoden des Aufrufenden Objektes aufzurufen. Ändert man element.args() auf z.b. _args und übergibt der Methode diese als Parameter, kann die selbe Logik auch aus einer Klasse heraus verwendet werden. void workWithCallingRecord() { common common; object object; formDataSource formDataSource; formRun formRun; inventDim inventDim; salesTable salesTable; int i; ; // Call method from calling record if( element.args() && element.args().record() ) { common = element.args().record(); if(common.isFormDataSource()) { info(tableId2Name(common.TableId)); if(formDataSourceHasMethod(common.dataSource(), identifierStr("someMethod"))) { object = common.dataSource(); object.someMethod(); } } } // Call method from calling form if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun')) { formRun = element.args().caller(); if(sysFormRun::hasMethod(formRun, identifierStr("someFormMethod"))) { object = formRun; object.someFormMethod(); } } // Get value from calling record if( element.args() && element.args().record() ) { common = element.args().record(); if(common.TableId == tableNum(salesTable)) { info(common.(fieldNum(salesTable, salesId))); } } // Get value from calling datasource (form with multiple datasources) if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun')) { formRun = element.args().caller(); for (i = 0; i <= formRun.dataSourceCount(); i++) { formDataSource = formRun.datasource(i); if (formDataSource && formDataSource.table() == tablenum(inventDim)) // Search for specific table { inventDim = formDataSource.cursor(); break; } } if(inventDim) { info(inventDim.InventLocationId); } } // Change data in calling datasource if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun')) { formRun = element.args().caller(); for (i = 0; i <= formRun.dataSourceCount(); i++) { formDataSource = formRun.datasource(i); if (formDataSource && formDataSource.table() == tablenum(salesTable)) // Search for specific table { salesTable = formDataSource.cursor(); break; } } if(salesTable) { // Update data salesTable.PurchOrderFormNum = "Some value"; salesTable.update(); } } // Refresh calling datasource if( element.args() && element.args().record() ) { common = element.args().record(); if(common.isFormDataSource()) { formDataSource = common.dataSource(); formDataSource.research(true); } } } |
Dynamics AX mit einem bestimmten Windowslogin starten
08.11.2009Microsoft Dynamics AX (Axapta)
Gegenüber früheren Versionen von Dynamics AX hat man - dank Integration des Active Directories - in AX 2009 kaum Möglichkeiten, die Anwendung als ein bestimmter Benutzer zu starten. Gerade dies ist aber notwendig, wenn man z.B. Änderungen in den Sicherheitseinstellungen/Berechtigungen überprüfen möchte. Für solche Fälle habe ich mir eine Batch-Datei (*.bat) geschrieben, die mir eine lokale AX-Installation mit einem bestimmten Windows-Login startet. Diese Batch-Datei öffnet ein Windows-Kommandozeilen-Fenster in welchem man zur Eingabe des Windows-Passworts aufgefordert wird. runas /user:domain\username "C:\Programme\Microsoft Dynamics AX\50\Client\Bin\Ax32.exe "C:\Programme\Microsoft Dynamics AX\50\MyConfigurationfile.axc"" Wenn man diese Befehlszeile direkt in der Eingabeaufforderung eingeben will, muss man den Befehl wie folgt leicht abwandeln: runas /user:domain\username "C:\Programme\Microsoft Dynamics AX\50\Client\Bin\Ax32.exe \"C:\Programme\Microsoft Dynamics AX\50\MyConfigurationfile.axc\"" Muss man ausser der Konfigurationsdatei noch weitere Parameter übergeben, kann man die Batch-Datei wie folgt erweitern: runas /user:domain\username "C:\Programme\Microsoft Dynamics AX\50\Client\Bin\Ax32.exe "C:\Programme\Microsoft Dynamics AX\50\MyConfigurationfile.axc" -aol=var -aolcode=j+eA4566458bsZReSO1Q==" Der selbe Befehl sähe, wenn man ihn über die Eingabeaufforderung eingeben wollte, wie folgt aus: runas /user:domain\username "C:\Programme\Microsoft Dynamics AX\50\Client\Bin\Ax32.exe \"C:\Programme\Microsoft Dynamics AX\50\MyConfigurationfile.axc\" -aol=var -aolcode=j+eA4566458bsZReSO1Q==" Alternativ dazu kann man sich auch der hier beschriebenen Lösung bedienen. Übrigens: Sollte die Konfigurationsdatei auf einem Netzlaufwerk liegen, so sollte man bei der Angabe des Dateipfades nicht dessen Laufwerksbuchstaben verwenden, sondern den vollen UNC-Pfad. Denn möglicherweise hat der Benutzer, mit dem ich die Applikation starten möchte, den einzelnen Netzwerklaufwerken andere Laufwerksbuchstaben zugewiesen als man selbst ;-) |
Geänderte oder neue Methoden von Klassen auflisten
01.11.2009Microsoft Dynamics AX (Axapta)
Im folgenden findet ihr einen Job, der in einer adaptierten Applikation alle Methoden von Klassen auflistet, die entweder erstellt wurden oder gegenüber dem Standard verändert wurden. static void ListChangedOrCreatedClassesMethods(Args _args) { SysDictClass SysDictClass; treeNode treeNode; treeNode treeNodeBase; treeNode treeNodeCustom; treeNode treeNodeClasses; UtilEntryLevel CurrentUtilEntryLevel; #AOT ; treeNodeClasses = TreeNode::findNode(#ClassesPath + #AOTRootPath); treeNodeClasses = treeNodeClasses.AOTfirstChild(); SysDictClass = new SysDictClass((treeNodeClasses.applObjectId())); setPrefix('List changed/created classes'); while(treeNodeClasses) { SysDictClass = new SysDictClass((treeNodeClasses.applObjectId())); setPrefix(SysDictClass.name()); treeNode = TreeNode::findNode(#ClassesPath + #AOTRootPath + SysDictClass.name() + #AOTRootPath); treeNode = treeNode.AOTfirstChild(); while(treeNode) { treeNodeBase = null; treeNodeCustom = null; // Partner if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::bup); if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::bus); // Solutions if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::sl3); if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::sl2); if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::sl1); // Hotfix if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::hfx); // Microsoft if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::glp); if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::gls); if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::syp); if( !treeNodeBase) treeNodeBase = treeNode.getNodeInLayer(UtilEntryLevel::sys); // Custom layers if( !treeNodeCustom) { treeNodeCustom = treeNode.getNodeInLayer(UtilEntryLevel::vap); CurrentUtilEntryLevel = UtilEntryLevel::vap; } if( !treeNodeCustom) { treeNodeCustom = treeNode.getNodeInLayer(UtilEntryLevel::var); CurrentUtilEntryLevel = UtilEntryLevel::var; } if( !treeNodeCustom) { treeNodeCustom = treeNode.getNodeInLayer(UtilEntryLevel::cup); CurrentUtilEntryLevel = UtilEntryLevel::cup; } if( !treeNodeCustom) { treeNodeCustom = treeNode.getNodeInLayer(UtilEntryLevel::cus); CurrentUtilEntryLevel = UtilEntryLevel::cus; } if( !treeNodeCustom) { treeNodeCustom = treeNode.getNodeInLayer(UtilEntryLevel::usp); CurrentUtilEntryLevel = UtilEntryLevel::usp; } if( !treeNodeCustom) { treeNodeCustom = treeNode.getNodeInLayer(UtilEntryLevel::usr); CurrentUtilEntryLevel = UtilEntryLevel::usr; } // Changed methods if(treeNodeBase) { if( treeNodeBase.AOTgetSource() != treeNode.AOTgetSource()) { warning(strFmt( "Method '%1' was changed in layer '%2'.", treeNode.treeNodeName(), enum2str(CurrentUtilEntryLevel))); } } // New created methods if( !treeNodeBase) { info(strFmt( "Method '%1' was created in layer '%2'.", treeNode.treeNodeName(), enum2str(CurrentUtilEntryLevel))); } treeNode = treeNode.AOTnextSibling(); } treeNodeClasses = treeNodeClasses.AOTnextSibling(); } } Ein ähnlicher Job der prinzipiell das Gleiche erledigt, allerdings für alle Tabellenmethoden, ist hier zu finden. |
|
|
|
|
|
|
Hinweis: Zu diesem Thema ist eine aktuellere Version verfügbar
Sollen in einem Formular nur bestimmte Felder zur Bearbeitung freigegeben sein, kann man die Eigenschaft allowEdit sämtlicher Felder der DataSource der Tabelle entsprechend umsetzen.
Einfacher geht’s mit folgendem Codebeispiel, welches in der init-Methode der DataSource eingebunden wurde und - im konkreten Fall in der Tabelle SalesLine - nur bei einem einzigen Feld die Bearbeitung erlaubt.
{
sqlDictionary sqlDictionary;
;
super();
while select sqlDictionary
where sqlDictionary.tabId == tableNum(salesLine)
&& sqlDictionary.fieldId != 0
{
if(sqlDictionary.name != "dataareaid" &&
sqlDictionary.name != "recversion" &&
sqlDictionary.name != "recId"
)
{
salesline_ds.object(sqlDictionary.fieldId).allowEdit(false);
}
}
salesline_ds.object(fieldNum(salesLine, blocked)).allowEdit(true);
}
Getestet in AX 3.0