Dynamics AX Blog - Seite 35
Bearbeiten von Formularfeldern beschränken II
21.08.2011Microsoft Dynamics AX (Axapta)
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. Im Gegensatz zu einem früher veröffentlichten Beitrag mit dem gleichen Thema werden bei diesem Codebeispiel auch Array-Felder korrekt berücksichtigt. public void init()
{ FormDataObject fdo; int f; SysDictTable sysDictTable; MapEnumerator fdoMapEnumerator; ; sysDictTable = new SysDictTable(tablenum(SalesLine)); for(f=1;f<=sysDictTable.fieldCnt();f++) { fdoMapEnumerator = new MapEnumerator(formDataSourceArrayFieldExtObjects(salesLine_ds, sysDictTable.fieldCnt2Id(f))); while (fdoMapEnumerator.moveNext()) { fdo = fdoMapEnumerator.currentValue(); if(fdo) { fdo.allowEdit(false); } } } fdo = salesLine_ds.object(fieldnum(SalesLine, QtyOrdered)); fdo.allowEdit(true); } Getestet in Dynamics AX 2009 |
Datensatzvorlagen ermitteln
12.08.2011Microsoft Dynamics AX (Axapta)
Wer einmal in die Verlegenheit kommt, ermitteln zu müssen ob für eine bestimmte Tabelle Datensatzvorlagen vorhanden sind, für den kann folgendes Code-Beispiel hilfreich sein. Im Beispiel wird ermittelt, wieviele Benutzer- bzw. Unternehmensvorlagen es für die Tabelle InventTable gibt und ob der aktuelle Benutzer sich den Vorlagendialog anzeigen lässt, wenn er/sie einen neuen Artikel anlegt. static void SysRecordTemplatesActive(Args _args) { tableId tableId = tableNum(inventTable); common common = new sysdictTable(tableId).makeRecord(); SysRecordTemplateStorageUser storageUser = SysRecordTemplateStorage::newCommon(common, SysRecordTemplateType::User); SysRecordTemplateStorageCompany storageCompany = SysRecordTemplateStorage::newCommon(common, SysRecordTemplateType::Company); sysRecordTemplateSelect sysRecordTemplateSelect; container userTemplates; container companyTemplates; ; // Liste der Vorlagen userTemplates = storageUser.get(); info(strFmt("Anzahl Benutzervorlagen für Tabelle %1: %2", new sysdictTable(tableId).label(), conLen(userTemplates))); companyTemplates = storageCompany.get(); info(strFmt("Anzahl Unternehmensvorlagen für Tabelle %1: %2", new sysdictTable(tableId).label(), conLen(companyTemplates))); // Soll der aktive Benutzer nach Vorlagen gefragt werden? sysRecordTemplateSelect = SysRecordTemplateSelect::newTableId(tableId); sysRecordTemplateSelect.load(); info(strFmt("Datensatzvorlagen für die Tabelle %1 in Verwendung: %2", new sysdictTable(tableId).label(), enum2str(sysRecordTemplateSelect.parmPrompt()))); } |
Berichte lassen sich nicht über die Stapelverarbeitung ausführen
06.07.2011Microsoft Dynamics AX (Axapta)
Wenn bei einem Benutzer der Register Stapel beim Aufruf eines Berichtes nicht angezeigt wird, kann dies u.U. daran liegen, daß der Benutzer keine oder unzureichende Berechtigung für den Sicherheitsschlüssel Stapelverarbeitungsbericht (SecurityKey BatchReport) hat.
|
Projekte nach einem bestimmten Objekt durchsuchen
29.06.2011Microsoft Dynamics AX (Axapta)
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. |
Berechtigung eines Benutzers für einen Sicherheitsschlüssel abfragen
24.06.2011Microsoft Dynamics AX (Axapta)
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
03.06.2011Microsoft Dynamics AX (Axapta)
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. |
|
|
|
|
|
|
Wer schon einmal eine Applikation inkl. Datenbank von einer Netzwerk-Domäne in eine andere übertragen hat, der kennt vielleicht die Situation. Man hat die Applikation und die Datenbank eingerichtet, kann sich in Dynamics AX aber nicht anmelden und erhält die Fehlermeldung:
Die Ursache dafür ist, daß in der Tabelle UserInfo - das ist jene Tabelle wo die AD-Benutzer verwaltet werden - natürlich noch die Benutzer der Ursprungsdomäne hinterlegt sind. Im einfachsten Fall ändert man in dieser Tabelle den Eintrag für den Administrator, indem man die Felder NetworkDomain, NetworkAlias und SID entsprechend ändert. NetworkDomain und NetworkAlias sind selbsterklärend, woher bekommt man aber die SID?
Eine einfache Internet-Recherche nach "GET SID" liefert einige Möglichkeiten, weniger bekannt ist aber, daß auch Dynamics AX 2009 selbst eine Methode zur Verfügung stellt, um die SID für einen Benutzer auszulesen.
Jetzt braucht man also nur noch ein anderes, bereits lauffähiges AX, wo man sich anmelden und den Job absetzen kann ;-)