<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/css" href="http://www.schweda.net/style_feed.css" ?>

<rss version="2.0" 
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
    xmlns:atom="http://www.w3.org/2005/Atom"	
	xmlns:dc="http://purl.org/dc/elements/1.1/" > 
<channel>
    <title>Heinz Schweda</title>
    <link>http://www.schweda.net/</link>
    <description>Meine Blog-Eintraege</description>
    <language>de-at</language>
    <copyright>Copyright 2006-2012</copyright>
    <generator>schweda.net</generator>
    <managingEditor>heinz.schweda@schweda.net</managingEditor>
    <webMaster>heinz.schweda@schweda.net</webMaster>
    <category>Blog</category>
	<atom:link href="http://www.schweda.net/blog_rss.php?icid=2" rel="self" type="application/rss+xml" />
<item>
<title>AX 2012: Standardfinanzdimension eines Datensatzes setzen</title>
<description><![CDATA[
<p>Der nachstehende Code soll zeigen, wie man in Dynamics AX 2012 bei einem Datensatz - im Beispiel handelt es sich um einen Debitor - die Standardfinanzdimensionen per X++ bef&uuml;llen kann.
</p>

<p>Im Beispiel werden mehrere Dimensionen mit Werten bef&uuml;llt. Bitte beachtet, da&szlig; die angef&uuml;hrten Dimensionen m&ouml;glicherweise in Euren AX-Installationen nicht vorhanden sind.
</p>

<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void setDefaultDimension4CustTable(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; CustTable custTable;<br />
<br />
&nbsp;&nbsp;&nbsp; RecId getDefaultDimension(container _c)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttribute dimensionAttribute;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttributeValue dimensionAttributeValue;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttributeValueSetStorage dimensionAttributeValueSetStorage;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; container dimensionCon;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name dimensionName;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str 255 dimensionValue;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValueSetStorage = new&nbsp; DimensionAttributeValueSetStorage();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=1;i&lt;=conLen(_c);i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionCon = conPeek(_c, i);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionName&nbsp; = conPeek(dimensionCon, 1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionValue = conPeek(dimensionCon, 2);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select dimensionAttribute<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where dimensionAttribute.Name == dimensionName;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(dimensionAttribute)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute, dimensionValue, false, true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValueSetStorage.addItem(dimensionAttributeValue);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return dimensionAttributeValueSetStorage.save();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ;<br />
<br />
&nbsp;&nbsp;&nbsp; try<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttsbegin;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; custTable = CustTable::find('9101', true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; custTable.DefaultDimension =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getDefaultDimension([<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&quot;Department&quot;,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '100'],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&quot;Debitor&quot;,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '3010'],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&quot;CustomerGroup&quot;,&nbsp;&nbsp; '80'],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&quot;ParentProject&quot;,&nbsp;&nbsp; '2000'],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&quot;CostCenter&quot;,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '07']<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ]);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; custTable.update();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttscommit;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(&quot;Update custtable.defaultDimension sucessfull.&quot;);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; catch<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw error(&quot;Error occured&quot;);<br />
&nbsp;&nbsp;&nbsp; }<br />
}
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Sat, 19 May 2012 10:55:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=427</link>
<comments>http://www.schweda.net/blog_ax.php?bid=427</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=427</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=427</wfw:commentRss>
</item>
<item>
<title>AX 2012: Standardfinanzdimension eines Datensatzes auslesen und Inhalt prüfen</title>
<description><![CDATA[
<p>Der folgende Job demonstriert, wie man den Inhalt&nbsp;der Standardfinanzdimensionen eines Datensatzes&nbsp;-&nbsp;im Beispiel jene eines Debitoren - per X++ pr&uuml;ft.
</p>

<p>Im Beispiel werden die Dimensionen namens <em>CustomerGroup</em>, <em>Debitor </em>und <em>NonExistingDimension </em>als zu pr&uuml;fen angegeben. Bitte beachtet, da&szlig; nicht alle Dimensionen in jeder AX-Instanz vorhanden sind. Vor allem letztere dient lediglich zur Demonstration, wie sich der Code verh&auml;lt, wenn eine Dimensionen ausgelesen werden soll, die es gar nicht gibt.
</p>

<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void validateDefaultDimensionValues(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; CustTable custTable = CustTable::find('9101', true);<br />
&nbsp;&nbsp;&nbsp; container validateCon;<br />
&nbsp;&nbsp;&nbsp; container helpCon;<br />
&nbsp;&nbsp;&nbsp; int ii;<br />
<br />
&nbsp;&nbsp;&nbsp; container getDimensionValue(RecId _dimensionAttributeValueSetRecId, container _c)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttributeValueSetItem dimensionAttributeValueSetItem;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttributeValue dimensionAttributeValue;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttribute dimensionAttribute;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Common dimensionValueEntity;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name dimensionName;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str 255 dimensionValue;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; container retCon;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=1;i&lt;=conLen(_c);i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionName&nbsp; = conPeek(_c, i);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( !DimensionAttribute::findByName(dimensionName))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; error(strFmt(&quot;Dimension %1 not found&quot;, dimensionName));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while select dimensionAttributeValueSetItem<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where&nbsp;&nbsp; dimensionAttributeValueSetItem.DimensionAttributeValueSet&nbsp;&nbsp; == _dimensionAttributeValueSetRecId<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Find the dimension 'value' (DimensionAttributeValue) that the set item points to.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue = DimensionAttributeValue::find(dimensionAttributeValueSetItem.DimensionAttributeValue);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Find the underlying attribute.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttribute = DimensionAttribute::find(dimensionAttributeValue.DimensionAttribute);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Use the helper class to obtain a reference to the underlying entity (can be anything)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionValueEntity = DimensionDefaultingControllerBase::findBackingEntityInstance(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; curext(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttribute,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue.EntityInstance);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(dimensionAttribute.Name == dimensionName)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retCon = conIns(retCon, conLen(retCon)+1, [dimensionAttribute.Name, dimensionAttributeValue.getValue()]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return retCon;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ;<br />
<br />
&nbsp;&nbsp;&nbsp; validateCon = getDimensionValue(custTable.DefaultDimension, [&quot;CustomerGroup&quot;, &quot;Debitor&quot;, &quot;NonExistingDimension&quot;]);<br />
&nbsp;&nbsp;&nbsp; for (ii=1;ii&lt;=conLen(validateCon);ii++)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; helpCon = conPeek(validateCon, ii);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(conPeek(helpCon, 1) == &quot;CustomerGroup&quot; &amp;&amp; conPeek(helpCon, 2) != custTable.CustGroup)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; warning(strFmt(&quot;Dimension %1 should be %2.&quot;, conPeek(helpCon, 1), conPeek(helpCon, 2)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(conPeek(helpCon, 1) == &quot;Debitor&quot; &amp;&amp; conPeek(helpCon, 2) != custTable.AccountNum)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; warning(strFmt(&quot;Dimension %1 should be %2.&quot;, conPeek(helpCon, 1), conPeek(helpCon, 2)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(conPeek(helpCon, 1) == &quot;NonExistingDimension&quot; &amp;&amp; conPeek(helpCon, 2) != custTable.AccountNum)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; warning(strFmt(&quot;Dimension %1 should be %2.&quot;, conPeek(helpCon, 1), conPeek(helpCon, 2)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
}
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Wed, 16 May 2012 21:22:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=430</link>
<comments>http://www.schweda.net/blog_ax.php?bid=430</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=430</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=430</wfw:commentRss>
</item>
<item>
<title>AX 2012: Benutzerdefinierte Finanzdimension anlegen</title>
<description><![CDATA[
<p>MIt Hilfe des folgenden Jobs kann in Dynamics AX 2012 ein neuer Eintrag f&uuml;r eine benutzerdefinierte Finanzdimension erstellt werden. Im Beispiel ist der Name der Dimension <em>ParentProject </em>und der einzuf&uuml;gende Wert ist <em>4600</em>.
</p>

<div style="padding: 5px; width: 460px; height: 240px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void createCustomDimensionValue(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; DimensionValueService dimensionValueService;<br />
&nbsp;&nbsp;&nbsp; DimensionValueContract dimensionValueContract;<br />
<br />
&nbsp;&nbsp;&nbsp; dimensionValueService = new DimensionValueService();<br />
&nbsp;&nbsp;&nbsp; dimensionValueContract = new DimensionValueContract();<br />
&nbsp;&nbsp;&nbsp; dimensionValueContract.parmDescription('Project 4500');<br />
&nbsp;&nbsp;&nbsp; dimensionValueContract.parmValue('4600');<br />
&nbsp;&nbsp;&nbsp; dimensionValueContract.parmDimensionAttribute('ParentProject');<br />
&nbsp;&nbsp;&nbsp; if(dimensionValueService.createDimensionValue(dimensionValueContract))<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(strFmt(&quot;Dimension value %1 for dimension %2 created&quot;, dimensionValueContract.parmValue(), dimensionValueContract.parmDimensionAttribute()));<br />
&nbsp;&nbsp;&nbsp; }<br />
}
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Mon, 14 May 2012 12:53:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=428</link>
<comments>http://www.schweda.net/blog_ax.php?bid=428</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=428</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=428</wfw:commentRss>
</item>
<item>
<title>AX 2012: Werte einer Finanzdimension auslesen</title>
<description><![CDATA[
<p>Der folgende Job demonstriert, wie man sich die Werte einer Finanzdimension - im Beispiel&nbsp; <em>Department </em>- per X++ ausgeben lassen kann.
</p>

<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void getValues4Dimension(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; DimensionValueService dimensionValueService;<br />
&nbsp;&nbsp;&nbsp; DimensionContract dimensionContract;<br />
&nbsp;&nbsp;&nbsp; List dimensionValueContractList;<br />
&nbsp;&nbsp;&nbsp; ListEnumerator listEnumerator ;<br />
&nbsp;&nbsp;&nbsp; DimensionValueContract dimensionValueContract;<br />
&nbsp;&nbsp;&nbsp; DimensionValue dimensionValue;<br />
<br />
&nbsp;&nbsp;&nbsp; dimensionValueService = new DimensionValueService();<br />
&nbsp;&nbsp;&nbsp; dimensionContract = new DimensionContract();<br />
&nbsp;&nbsp;&nbsp; dimensionContract.parmDimensionName('Department');<br />
&nbsp;&nbsp;&nbsp; dimensionValueContractList = dimensionValueService.getDimensionValues(dimensionContract);<br />
&nbsp;&nbsp;&nbsp; listEnumerator = dimensionValueContractList.getEnumerator();<br />
<br />
&nbsp;&nbsp;&nbsp; setPrefix(strFmt(&quot;Dimension %1: &quot;, dimensionContract.parmDimensionName()));<br />
&nbsp;&nbsp;&nbsp; while(listEnumerator.moveNext())<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionValueContract = listEnumerator.current();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionValue = dimensionValueContract.parmValue();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(dimensionValue);<br />
&nbsp;&nbsp;&nbsp; }<br />
}
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Sun, 13 May 2012 20:45:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=431</link>
<comments>http://www.schweda.net/blog_ax.php?bid=431</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=431</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=431</wfw:commentRss>
</item>
<item>
<title>AX 2012: Kontostruktur eines Hauptkontos ermitteln</title>
<description><![CDATA[
<p>M&ouml;chte man f&uuml;r das Hauptkonto einer Position einer Allgemeinen Erfassung ermitteln, kann man dies mit Hilfe des nachstehenden Codes tun.
</p>

<div style="padding: 5px; width: 460px; height: 140px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void getAccountStructureFromLedgerDimension(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; ledgerJournalTrans ledgerJournalTrans;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; select ledgerJournalTrans<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where ledgerJournalTrans.JournalNum == '000151_010';&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; info(DimensionStorage::getAccountStructureFromLedgerDimension(ledgerJournalTrans.LedgerDimension).Name);<br />
}
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Fri, 11 May 2012 11:02:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=433</link>
<comments>http://www.schweda.net/blog_ax.php?bid=433</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=433</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=433</wfw:commentRss>
</item>
<item>
<title>AX 2012: Standardfinanzdimension eines Datensatzes auslesen und ausgeben</title>
<description><![CDATA[
<p>Im folgenden Job werden die eingetragenen Standardfinanzdimensionen eines Datensatzes - im konkreten Fall die eines bestimmten Debitoren - ausgegeben.
</p>

<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void getDimensionsFromDefaultDimension(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; DimensionAttributeValueSet dimensionAttributeValueSet;<br />
&nbsp;&nbsp;&nbsp; DimensionAttributeValueSetItem dimensionAttributeValueSetItem;<br />
&nbsp;&nbsp;&nbsp; DimensionAttributeValue&nbsp;dimensionAttributeValue;<br />
&nbsp;&nbsp;&nbsp; DimensionAttribute dimensionAttribute;<br />
&nbsp;&nbsp;&nbsp; Common dimensionValueEntity;<br />
<br />
&nbsp;&nbsp;&nbsp; dimensionAttributeValueSet = DimensionAttributeValueSet::find(CustTable::find('9101').DefaultDimension);<br />
<br />
&nbsp;&nbsp;&nbsp; // Find all of the 'value set items' linked against the 'value set'<br />
&nbsp;&nbsp;&nbsp; while select dimensionAttributeValueSetItem<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where&nbsp;&nbsp; dimensionAttributeValueSetItem.DimensionAttributeValueSet&nbsp;== dimensionAttributeValueSet.RecId<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Find the dimension 'value' (DimensionAttributeValue) that the set item points to.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue = DimensionAttributeValue::find(dimensionAttributeValueSetItem.DimensionAttributeValue);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Find the underlying attribute.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttribute = DimensionAttribute::find(dimensionAttributeValue.DimensionAttribute);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Use the helper class to obtain a reference to the underlying entity (can be anything)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionValueEntity = DimensionDefaultingControllerBase::findBackingEntityInstance(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; curext(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttribute,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue.EntityInstance);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(strFmt(&quot;%1: %2&quot;, dimensionAttribute.Name, dimensionAttributeValue.getValue()));<br />
&nbsp;&nbsp;&nbsp; }<br />
}
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Wed, 09 May 2012 20:00:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=432</link>
<comments>http://www.schweda.net/blog_ax.php?bid=432</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=432</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=432</wfw:commentRss>
</item>
<item>
<title>AX 2012: Dimensionen einer Position einer Allgemeines Erfassung per X++ auslesen</title>
<description><![CDATA[
<p>Wenn man bei einer Position einer Allgemeinen Erfassung, welche gegen ein Sachkonto/Hauptkonto bucht, per X++ die eingetragenen Dimensionen auslesen m&ouml;chte, kann der folgende Code m&ouml;glicherweise hilfreich sein.
</p>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax2012_ledgerjournaltrans_ledgeraccount.JPG"><img width="465" height="289" title="Position einer Allgemeinen Erfassung" alt="Position einer Allgemeinen Erfassung" border="0" src="http://www.schweda.net/pictures/blogpics/tb_ax2012_ledgerjournaltrans_ledgeraccount.JPG" /></a>
</p>


<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void getLedgerDimensionData(Args _args) <br />
{ <br />
&nbsp;&nbsp;&nbsp; LedgerJournalTrans ledgerJournalTrans; <br />
<br />
&nbsp;&nbsp;&nbsp; void getDimensionsFromDefaultDimension(RecId _dimensionrecid) <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttributeValueSet dimensionAttributeValueSet; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttributeValueSetItem dimensionAttributeValueSetItem; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttributeValue&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionAttribute dimensionAttribute; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Common dimensionValueEntity; <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValueSet = DimensionAttributeValueSet::find(_dimensionrecid); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Find all of the 'value set items' linked against the 'value set' <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while select dimensionAttributeValueSetItem <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where&nbsp;&nbsp; dimensionAttributeValueSetItem.DimensionAttributeValueSet == dimensionAttributeValueSet.RecId <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Find the dimension 'value' (DimensionAttributeValue) that the set item points to. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue = DimensionAttributeValue::find(dimensionAttributeValueSetItem.DimensionAttributeValue); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Find the underlying attribute. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttribute = DimensionAttribute::find(dimensionAttributeValue.DimensionAttribute); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Use the helper class to obtain a reference to the underlying entity (can be anything) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionValueEntity = DimensionDefaultingControllerBase::findBackingEntityInstance( <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; curext(), <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttribute, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue.EntityInstance); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(strFmt(&quot;%1: %2 - %3&quot;, dimensionAttribute.Name, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue.getValue(), <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dimensionAttributeValue.getName() <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; ; <br />
<br />
&nbsp;&nbsp;&nbsp; while select ledgerJournalTrans <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where ledgerJournalTrans.JournalNum == '000151_010' <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get main account data <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(strFmt(&quot;Main account display value: %1&quot;, DimensionAttributeValueCombination::find(ledgerJournalTrans.LedgerDimension).DisplayValue)); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(MainAccount::find(DimensionAttributeValueCombination::find(ledgerJournalTrans.LedgerDimension).MainAccount)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(strFmt(&quot;Main account: %1 - %2&quot;, MainAccount::find(DimensionAttributeValueCombination::find(ledgerJournalTrans.LedgerDimension).MainAccount).MainAccountId, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MainAccount::find(DimensionAttributeValueCombination::find(ledgerJournalTrans.LedgerDimension).MainAccount).Name)); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(strFmt(&quot;Account structure: %1&quot;, DimensionStorage::getAccountStructureFromLedgerDimension(ledgerJournalTrans.LedgerDimension).Name)); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get dimension values <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setPrefix(&quot;Dimension values&quot;); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getDimensionsFromDefaultDimension(DimensionStorage::getDefaultDimensionFromLedgerDimension(ledgerJournalTrans.LedgerDimension)); <br />
&nbsp;&nbsp;&nbsp; } <br />
}
</div>

<p>Als Ergebnis des obigen Jobs wird ein Infolog ausgegeben.
</p>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax2012_ledgerjournaltrans_ledgeraccount_infolog.JPG"><img width="465" height="239" title="Infolog" alt="Infolog" border="0" src="http://www.schweda.net/pictures/blogpics/tb_ax2012_ledgerjournaltrans_ledgeraccount_infolog.JPG" /></a>
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Wed, 09 May 2012 09:28:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=435</link>
<comments>http://www.schweda.net/blog_ax.php?bid=435</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=435</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=435</wfw:commentRss>
</item>
<item>
<title>AX 2012: Datensätze mit einer bestimmten Dimension ausgeben</title>
<description><![CDATA[
<p>Der folgende Job listet alle Debitoren auf, bei welchen in der Dimension <em>CustomerGroup </em>der Wert <em>80 </em>eingetragen ist.
</p>

<p>Der interessante Teil des Jobs ist die Methode <em><strong>addDimensionAttributeRange </strong></em>der Klasse <em>SysQuery</em>, da diese sich um das&nbsp;Verkn&uuml;pfen der ben&ouml;tigten Datenquellen k&uuml;mmert.
</p>

<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void getRecords4DimensionValue(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; Query query;<br />
&nbsp;&nbsp;&nbsp; QueryBuildDataSource queryBuildDataSource;<br />
&nbsp;&nbsp;&nbsp; QueryBuildRange queryBuildRange;<br />
&nbsp;&nbsp;&nbsp; QueryRun queryRun;<br />
&nbsp;&nbsp;&nbsp; CustTable custTable;<br />
<br />
&nbsp;&nbsp;&nbsp; query = new Query();<br />
&nbsp;&nbsp;&nbsp; queryBuildDataSource = query.addDataSource(tableNum(CustTable));<br />
<br />
&nbsp;&nbsp;&nbsp; queryBuildRange = SysQuery::addDimensionAttributeRange( query,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queryBuildDataSource.name(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;DefaultDimension&quot;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DimensionComponent::DimensionAttribute,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queryValue(&quot;80&quot;),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;CustomerGroup&quot;);<br />
<br />
&nbsp;&nbsp;&nbsp; queryRun = new QueryRun(query);<br />
&nbsp;&nbsp;&nbsp; while(queryRun.next())<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; custTable = queryRun.get(tableNum(CustTable));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(custTable.name());<br />
&nbsp;&nbsp;&nbsp; }<br />
}
</div>

<p>Die Klasse SysQuery stellt &uuml;brigens zahlreiche weitere &auml;hnliche Funktionen zur Verf&uuml;gung, um mit Dimensionswerten zu arbeiten.
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Tue, 08 May 2012 18:06:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=434</link>
<comments>http://www.schweda.net/blog_ax.php?bid=434</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=434</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=434</wfw:commentRss>
</item>
<item>
<title>AX 2012: ID, LegacyID und Origin</title>
<description><![CDATA[
<p>&nbsp;
</p>

<table>
    <tbody>
        <tr valign="top">
            
<td><strong>ID</strong>
</td>
            
<td>
            
<p>Ist eine sogenannte installations-spezifische ID,  d.h. ein und dasselbe Objekt kann in unterschiedlichen Umgebungen eine andere ID  aufweisen.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</p>
            
<p>Die ID wird u.a. zum Zeitpunkt des Importes eines  Model per AXUTIL vergeben Somit ist die ID aus Entwicklersicht zu  vernachl&auml;ssigen.
</p>
            
<p>Ein Model-File enth&auml;lt z.B. keine IDs! Auch per  Export/Import-Funktion erstellte Exportfiles mit Daten enthalten keine IDs  (lediglich GUIDs)
</p>
            
</td>
        </tr>
        <tr valign="top">
            
<td><strong>LegacyID</strong>
</td>
            
<td>
            
<p>Ist nur bei &quot;alten&quot; Objekten gesetzt, die es schon  in fr&uuml;heren Versionen von Dynamics AX gab. Bei neuen Elementen wird dieses  LegacyID nicht mehr vergeben.
</p>
            
<p>Somit ist diese LegacyID f&uuml;r einen Entwickler nicht relevant.
</p>
            
</td>
        </tr>
        <tr valign="top">
            
<td><strong>Origin</strong>
</td>
            
<td>
            
<p>Ist eine GUID, die beim Erstellen eines Elementes  zugewiesen wird und nicht mehr ver&auml;ndert wird.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</p>
            
<p>Diese dient dazu, ein Objekt eindeutig zu  identifizieren, weil die ID in unterschiedlichen Umgebungen (Entwicklungsumgebung vs. Produktivumgebung) ja  eine andere sein kann.
</p>
            
<p>Angenommen in AX7 w&uuml;rde eine in AX 2012 bereits  vorhandene Klasse umbenannt werden, k&ouml;nnte sie weder &uuml;ber die ID noch &uuml;ber den  Namen als das selbe Objekt erkannt werden, deshalb wurde diese GUID  eingef&uuml;hrt.
</p>
            
<p>Bei Tests innerhalb einer Windows-Dom&auml;ne habe ich  festgestellt, da&szlig; die Origin auch beim Import von Models/XPOs mit neuen Objekten  von der Quell- in die Zielumgebung &uuml;bernommen wird (hingegen sich die ID  ver&auml;ndert hat).&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</p>
            
<p><em>Wichtig</em>: &Uuml;ber die Funktion Export/Import erstellte  Export-Dateien enthalten GUIDs, keine Ids (im Gegensatz zu z.B. AX  2009)
</p>
            
</td>
        </tr>
    </tbody>

</table>

<p>Ein Must-Read zu dem Thema ist freilich: <a href="http://blogs.msdn.com/b/mfp/archive/2011/07/11/the-solution-to-the-element-id-problem.aspx">http://blogs.msdn.com/b/mfp/archive/2011/07/11/the-solution-to-the-element-id-problem.aspx</a>
</p>

<p>&nbsp;
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Tue, 08 May 2012 15:57:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=425</link>
<comments>http://www.schweda.net/blog_ax.php?bid=425</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=425</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=425</wfw:commentRss>
</item>
<item>
<title>Formular als Dialog verwenden</title>
<description><![CDATA[
<p>Im AOT befinden sich einige tutorial-Objekte, die dem Entwickler dabei helfen k&ouml;nnen, die eine oder andere Anforderung zu l&ouml;sen. Eine dieser Klassen ist die Klasse <em>tutorial_RunbaseForm</em>, die erkl&auml;rt wie man statt einem Dialog ein eigens erstelltes Formular als Dialog verwendet.
</p>

<p>Auf Basis dieses Turorials habe ich in Dynamics AX 2012 eine Anforderung wie folgt gel&ouml;st:
</p>


<p>In der Klasse <em>wmsArrivalStart </em>- das ist jene Klasse, die aus der Wareneingangs&uuml;bersicht aus aufgerufen werden kann und Wareneingangsjournale erstellt - eine neue Methode <em>MyDialog </em>eingebaut, die ein Formular namens <em>MyWMSArravialStart </em>als Dialog aufruft. Diesem Formular wird eine tempor&auml;re Tabelle <em>wmsArrivalDetailTmp </em>&uuml;bergeben und in einem Grid dargestellt.
</p>

<p>Das Formular baut auf Basis dieser Tabelle <em>wmsArrivalDetailTmp </em>eine weitere tempor&auml;re Tabelle namens <em>TmpWMSArrivalStartReturn </em>auf und retourniert diese an die Klasse <em>WMSArrivalStart</em>.
</p>

<p>Die Methode <em>MyDialog </em>wird von der <em>run</em>-Methode der Klasse <em>WMSArrivalStart </em>aus aufgerufen und &ouml;ffnet das Formular <em>MyWMSArrivalStart</em>. Dabei wird diesem Formular &uuml;ber eine entsprechende Parameter-Methode&nbsp; die Tabelle <em>wmsArrivalDetailTmp </em>&uuml;bergeben.&nbsp;Auf Basis dieser Tabelle wird im Formular eine tempor&auml;re Tabelle <em>TmpWMSArrivalStart </em>aufgebaut und in einem Grid angezeigt. Hat der Benutzer in diesem Grid seine Eingaben gemacht,&nbsp; wird diese tempor&auml;re Tabelle &uuml;ber die Methode <em>getTmpWMSArrivalStart </em>an die Klasse retourniert.
</p>

<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public static client boolean MyDialog(wmsArrivalDetailTmp _wmsArrivalDetailTmp)<br />
{<br />
&nbsp;&nbsp;&nbsp; DialogRunbase DialogRunbase;<br />
&nbsp;&nbsp;&nbsp; Object formRun;<br />
&nbsp;&nbsp;&nbsp; wmsArrivalDetailTmp wmsArrivalDetailTmpLocal;<br />
&nbsp;&nbsp;&nbsp; TmpWMSArrivalStart TmpWMSArrivalStartReturn;<br />
<br />
&nbsp;&nbsp;&nbsp; wmsArrivalDetailTmpLocal.setTmpData(_wmsArrivalDetailTmp);<br />
<br />
&nbsp;&nbsp;&nbsp; DialogRunbase = Dialog::newFormnameRunbase(formstr(MyWMSArrivalStart),null);<br />
<br />
&nbsp;&nbsp;&nbsp; DialogRunbase.run(false);<br />
<br />
&nbsp;&nbsp;&nbsp; if(DialogRunbase.formRun() &amp;&amp; sysFormRun::hasMethod(DialogRunbase.formRun(), identifierStr(&quot;parmWmsArrivalDetailTmp&quot;)))<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; formRun = DialogRunbase.formRun();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; formRun.parmWmsArrivalDetailTmp(wmsArrivalDetailTmpLocal);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw error(error::wrongUseOfFunction(funcName()));<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; DialogRunbase.run();<br />
<br />
&nbsp;&nbsp;&nbsp; DialogRunbase.wait();&nbsp;&nbsp; // Waits for user-input<br />
<br />
&nbsp;&nbsp;&nbsp; if(formRun &amp;&amp; sysFormRun::hasMethod(formRun, identifierStr(&quot;getTmpWMSArrivalStart&quot;)))<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpWMSArrivalStartReturn = formRun.getTmpWMSArrivalStart();<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; while select TmpWMSArrivalStartReturn<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // do something...<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; return DialogRunbase.closedOk();<br />
}
</div>

<p>Aufruf der Methode aus der <em>run</em>-Methode der Klasse <em>wmsStartArrival</em>
</p>

<div style="padding: 5px; width: 460px; height: 160px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">protected WMSJournalId run()<br />
{<br />
&nbsp;&nbsp;&nbsp; //...code...<br />
&nbsp;&nbsp;&nbsp; if (!WMSArrivalStart::MyDialog(wmsArrivalDetailTmp))<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &quot;&quot;;&nbsp;&nbsp;&nbsp; // Empty WMSJournalId<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; //...code...<br />
}
</div>

<p>In der <em>run</em>-Methode des Formulares wird die Methode <em>fillTables </em>aufgerufen, welche die von der Klasse &uuml;bergebenen Daten verarbeitet (&uuml;ber die Methode <em>parmWmsArrivalDetailTmp</em>)
</p>

<div style="padding: 5px; width: 460px; height: 120px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public void run()<br />
{<br />
&nbsp;&nbsp;&nbsp; this.fillTables();<br />
<br />
&nbsp;&nbsp;&nbsp; super();<br />
}
</div>

<p>Die Methode <em>parmWmsArrivalDetailTmp </em>dient zum &Uuml;bergeben der Datens&auml;tze der Tabelle <em>WmsArrivalDetailTmp</em>
</p>

<div style="padding: 5px; width: 460px; height: 120px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public wmsArrivalDetailTmp parmWmsArrivalDetailTmp(WmsArrivalDetailTmp _wmsArrivalDetailTmp = wmsArrivalDetailTmp)<br />
{<br />
&nbsp;&nbsp;&nbsp; wmsArrivalDetailTmp = _wmsArrivalDetailTmp;<br />
<br />
&nbsp;&nbsp;&nbsp; return wmsArrivalDetailTmp;<br />
}
</div>

<p>Die Methode <em>fillTables </em>baut auf Basis der Tabelle <em>WmsArrivalDetailTmp </em>eine weitere Tabelle auf. Diese Tabelle dient gleichzeitig als DataSource des Formulares und wird in einem Grid dargestellt.
</p>

<div style="padding: 5px; width: 460px; height: 120px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">private void fillTables()<br />
{<br />
&nbsp;&nbsp;&nbsp; while select WMSArrivalDetailTmp<br />
&nbsp;&nbsp;&nbsp; where WMSArrivalDetailTmp.Selected&nbsp;&nbsp; == NoYes::Yes<br />
&nbsp;&nbsp;&nbsp; &amp;&amp;&nbsp;&nbsp;&nbsp; WMSArrivalDetailTmp.InventQty&nbsp; &gt;&nbsp; 0<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpWMSArrivalStartReturn.itemid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = WMSArrivalDetailTmp.ItemId;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpWMSArrivalStartReturn.InventTransId&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = WMSArrivalDetailTmp.InventTransId;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpWMSArrivalStartReturn.WMSStandardPalletQuantity&nbsp;&nbsp;&nbsp; = InventTable::find(TmpWMSArrivalStartReturn.itemid).standardPalletQuantity;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpWMSArrivalStartReturn.WMSPalletCount&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = WMSArrivalDetailTmp.NoOfPallets;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpWMSArrivalStartReturn.insert();<br />
&nbsp;&nbsp;&nbsp; }<br />

<p>&nbsp;&nbsp;&nbsp; TmpWMSArrivalStart.setTmpData(TmpWMSArrivalStartReturn);<br />
<br />
&nbsp;&nbsp;&nbsp; TmpWMSArrivalStart_ds.executeQuery();<br />
}
</p>

</div>

<p>Klickt der Benutzer auf den OK-Button des Formulares wird &uuml;ber die Methode <em>getTmpWMSArrivalStart </em>der Inhalt der Tabelle <em>TmpWMSArrivalStart </em>an die Klasse retourniert.
</p>

<div style="padding: 5px; width: 460px; height: 80px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public TmpWMSArrivalStart getTmpWMSArrivalStart()<br />
{<br />
&nbsp;&nbsp;&nbsp; return TmpWMSArrivalStartReturn;<br />
}
</div>

<p>Abschliessend noch ein paar Anmerkungen zum Formular selbst:
</p>

<ul>
    
<li>Die Form muss eine Gruppe namens <em>dialogStartGrp </em>enthalten
</li>
    
<li>Die Form ben&ouml;tigt auch die entsprechenden Buttons (daf&uuml;r am besten die gesamte Gruppe <em>BottomButtonGrp </em>des Formulares<em> tutorial_RunbaseForm</em> &uuml;bernehmen
</li>

</ul>

<p>Das Beispiel funktioniert prinzipiell in AX 2009 genauso wie in AX 2012.
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Fri, 06 Apr 2012 22:37:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=350</link>
<comments>http://www.schweda.net/blog_ax.php?bid=350</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=350</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=350</wfw:commentRss>
</item>
<item>
<title>Event-Handling in Dynamics AX 2012</title>
<description><![CDATA[
<p>Eine wichtige Neuerung von AX 2012 sind die sogenannten <strong>Event-Handler</strong>. Diese Event-Handler sind eine elegante M&ouml;glichkeit, die Funktionalit&auml;t von AX 2012 zu erweitern, ohne dabei den Standardcode zu ver&auml;ndern. Dies soll vor allem sp&auml;tere Releaseupdates von Dynamics AX 2012 erheblich erleichtern.
</p>

<p>Prinzipiell unterscheidet man dabei zwischen Event-Handler die vor (PRE) bzw. nach (POST) dem Originalcode ausgef&uuml;hrt werden sollen, wobei jede der beiden Varianten ihre eigenen M&ouml;glichkeiten bieten. Pre-Event-Handler k&ouml;nnen die Original-Parameter der ausl&ouml;senden Methode ver&auml;ndern wogegen Post-Event-Handler den R&uuml;ckgabewert der ausl&ouml;senden Methode ver&auml;ndern k&ouml;nnen.
</p>

<p>Die folgenden drei Beispiele sollen die Verwendung dieser Event-Handler verdeutlichen.
</p>

<p><strong><em>Beispiel 1:</em></strong><em> Es soll der Inhalt des Feldes Suchbegriff der Artikeldetails dahingehend gepr&uuml;ft werden, da&szlig; zumindest 5 Zeichen eingegeben wurden.</em>
</p>


<p>In fr&uuml;heren Versionen von Dynamics AX h&auml;tte man f&uuml;r eine solche Pr&uuml;fung &uuml;blicherweise die <em>validateWrite </em>der Tabelle <em>inventTable </em>ver&auml;ndert - in AX 2012 erstellen wir statt dessen eine Klasse <em>MyInventTableEventHandler </em>mit einer Methode <em>inventTableValidateWritePostEventHandler </em>und verkn&uuml;pfen die Methode mit der <em>validateWrite</em>.
</p>

<p title="gotodetail">&nbsp;<a href="http://www.schweda.net/pictures/blogpics/ax2012_myinventtableeventhandler.jpg" target="_blank"><img width="339" border="0" height="53" src="http://www.schweda.net/pictures/blogpics/ax2012_myinventtableeventhandler.jpg" alt="Screenshot MyInventTableEventHandler" title="Screenshot MyInventTableEventHandler" /></a>
</p>

<p><u>Schritt 1: Erstellen der Klasse und Methode</u>
</p>

<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">class MyInventTableEventHandler <br />
{ <br />
} <br />
<br />
public static void inventTableValidateWritePostEventHandler(XppPrePostArgs _args) <br />
{ <br />
&nbsp;&nbsp;&nbsp; inventTable inventTable; <br />
<br />
&nbsp;&nbsp;&nbsp; inventTable = _args.getThis(); <br />
<br />
&nbsp;&nbsp;&nbsp; if (strLen(inventTable.NameAlias) &lt; 5) <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; warning(strFmt('Field &quot;%1&quot; should contain at least 5 characters.', fieldPName(inventTable, NameAlias))); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Set return value of the original method <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _args.setReturnValue(false); <br />
&nbsp;&nbsp;&nbsp; } <br />
}
</div>

<p><br />
<br />
<u>Schritt 2: Verkn&uuml;pfen der Methode mit der Tabelle</u>
</p>

<p>Per Drag &amp; Drop ziehen wir die Methode <em>inventTableValidateWritePostEventHandler </em>auf die <em>validateWrite </em>der <em>inventTable</em>.
</p>

<p><a href="http://www.schweda.net/pictures/blogpics/ax2012_myinventtableeventhandler_subscription.jpg" target="_blank"><img width="248" border="0" height="36" src="http://www.schweda.net/pictures/blogpics/ax2012_myinventtableeventhandler_subscription.jpg" title="Screenshot Subscription" alt="" /></a>
</p>

<p>Nun m&uuml;ssen wir noch festlegen, wann dieses Event ausgef&uuml;hrt werden soll, in unserem Fall w&auml;hlen wir die Variante Post.
</p>

<p><a href="http://www.schweda.net/pictures/blogpics/ax2012_myinventtableeventhandler_properties.jpg" target="_blank"><img width="465" border="0" height="152" src="http://www.schweda.net/pictures/blogpics/ax2012_myinventtableeventhandler_properties_small.jpg" alt="Screenshot Properties" title="Screenshot Properties" /></a>&nbsp;
</p>

<p>&nbsp;
</p>

<p><br />
<strong><em>Beispiel 2:</em></strong><em> Auch in diesem Beispiel soll der Inhalt des Feldes Suchbegriff der Artikeldetails gepr&uuml;ft werden, allerdings nicht erst beim Speichern des Datensatzes sondern gleich nach der Eingabe. </em>
</p>

<p>In fr&uuml;heren Versionen von Dynamics AX h&auml;tten wir hierf&uuml;r die Methode <em>validateField</em> entspechend angepasst, in meinem Beispiel verwende ich die Methode <em>validateField</em> als Ausl&ouml;ser des Events.
</p>

<p>Im Gegensatz zum Beispiel 1 verf&uuml;gt die Methode <em>validateField </em>&uuml;ber zwei Paramter, die selbstverst&auml;ndlich auch durch Event-Handler genutzt werden k&ouml;nnen. Auch dieses Mal handelt es sich um einen Post-Event-Handler.
</p>

<p><u>Schritt 1: Erstellen der Klasse und Methode</u>
</p>

<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">class MyInventTableEventHandler <br />
{ <br />
} <br />
<br />
public static void inventTableValidateFieldPostEventHandler(XppPrePostArgs _args) <br />
{ <br />
&nbsp;&nbsp;&nbsp; inventTable inventTable; <br />
&nbsp;&nbsp;&nbsp; FieldName fieldName; <br />
&nbsp;&nbsp;&nbsp; int arrayIndex; <br />
<br />
&nbsp;&nbsp;&nbsp; if(_args.getCalledWhen() != XppEventHandlerCalledWhen::Post) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw error(error::wrongUseOfFunction(funcName())); <br />
<br />
&nbsp;&nbsp;&nbsp; inventTable = _args.getThis(); <br />
<br />
&nbsp;&nbsp;&nbsp; // First parm _fieldName of the original method <br />
&nbsp;&nbsp;&nbsp; fieldName = _args.args().valueIndex(1); <br />
<br />
&nbsp;&nbsp;&nbsp; // Second parm _arrayIndex of the original method <br />
&nbsp;&nbsp;&nbsp; arrayIndex = _args.args().valueIndex(2); <br />
<br />
&nbsp;&nbsp;&nbsp; switch(fieldName) <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case fieldStr(InventTable, NameAlias): <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (strLen(inventTable.NameAlias) &lt; 5) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; warning(strFmt('Field &quot;%1&quot; should contain at least 5 characters.', fieldPName(inventTable, NameAlias))); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Set return value of the original method <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _args.setReturnValue(false); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; <br />
&nbsp;&nbsp;&nbsp; } <br />
}
</div>

<p><br />
<u>Schritt 2: Verkn&uuml;pfen der Methode mit der Tabelle</u>
</p>

<p>Per Drag &amp; Drop ziehen wir die Methode <em>inventTableValidateFieldPostEventHandler </em>auf die <em>validateField </em>der <em>inventTable</em>. Nun m&uuml;ssen wir noch festlegen, wann dieses Event ausgef&uuml;hrt werden soll, in unserem Fall w&auml;hlen wir die Variante Post.
</p>

<p>Hinweis: Alternativ zu _args.args().valueIndex() kann man die Parameter der Original-Methode auch wie folgt abfragen:
</p>

<div style="padding: 5px; width: 460px; height: 100px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">&nbsp;&nbsp;&nbsp; // First parm _fieldName of the original method <br />
&nbsp;&nbsp;&nbsp; fieldName = _args.getArg(identifierStr(_fieldName)); <br />
&nbsp;&nbsp;&nbsp; // Second parm _arrayIndex of the original method <br />
&nbsp;&nbsp;&nbsp; arrayIndex = _args.getArg(identifierStr(_ArrayIndex));
</div>

<p>&nbsp;
</p>

<p><br />
<strong><em>Beispiel 3: </em></strong><em>Bei Aktualisieren eines Datensatzes in den Artikeldetails soll das Feld Suchbegriff mit der Artikelnummer gef&uuml;llt werden, wenn das Feld Suchbegriff leer ist. </em>
</p>

<p>In Versionen vor Dynamics AX 2012 h&auml;tten wir gewohnterweise die <em>update</em>-Methode ver&auml;ndert, in dieser Version verwenden wir Sie als Ausl&ouml;ser des Events.<br />
<br />
<u>Schritt 1: Erstellen der Klasse und Methode</u>
</p>

<div style="padding: 5px; width: 460px; height: 300px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">class MyInventTableEventHandler <br />
{ <br />
} <br />
<br />
public static void inventTableUpdatePreEventHandler(XppPrePostArgs _args) <br />
{ <br />
&nbsp;&nbsp;&nbsp; inventTable inventTable; <br />
<br />
&nbsp;&nbsp;&nbsp; if(_args.getCalledWhen() != XppEventHandlerCalledWhen::Pre) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw error(error::wrongUseOfFunction(funcName())); <br />
<br />
&nbsp;&nbsp;&nbsp; inventTable = _args.getThis(); <br />
<br />
&nbsp;&nbsp;&nbsp; if( !inventTable.NameAlias) <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inventTable.NameAlias = inventTable.ItemId; <br />
&nbsp;&nbsp;&nbsp; } <br />
}
</div>

<p><br />
<u>Schritt 2: Verkn&uuml;pfen der Methode mit der Tabelle</u><br />
<br />
Per Drag &amp; Drop ziehen wir die Methode <em>inventTableUpdatePreEventHandler </em>auf die update der inventTable. Nun m&uuml;ssen wir noch festlegen, wann dieses Event ausgef&uuml;hrt werden soll, in unserem Fall w&auml;hlen wir die Variante Pre.
</p>

<p>&nbsp;
</p>

<p><em><strong>Weitere Hinweise</strong></em>
</p>

<p>Selbstverst&auml;ndlich kann eine Klasse mehrere Methoden enthalten die als Event-Handler benutzt werden, so k&ouml;nnten wir also alle drei oben beschriebenen Methoden in nur einer Klasse kombinieren.
</p>

<p>Weiters ist es nat&uuml;rlich auch m&ouml;glich, eine Event-Handler-Methode derart zu programmieren, als da&szlig; sie sowohl als Pre- als auch als Post-Event-Handler verwendet werden kann. Abgefragt werden kann dies - wie in den obigen Beispielen ansatzweise dargestellt &uuml;ber die Abfrage von <em>getCalledWhen </em>der <em>XppPrePostArgs</em>.<br />
Auch k&ouml;nnen wir mehrere Event-Handler mit eine Methode verkn&uuml;pfen, die Reihenfolge der Ausf&uuml;hrung ist allerdings nicht steuerbar.
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Sun, 25 Mar 2012 20:49:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=424</link>
<comments>http://www.schweda.net/blog_ax.php?bid=424</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=424</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=424</wfw:commentRss>
</item>
<item>
<title>Abfragen der aktiven Lagerungsdimensionen</title>
<description><![CDATA[
<p>Um f&uuml;r einen Artikel &uuml;ber X++ zu ermitteln, ob eine bestimmte Lagerungsdimension verwendet wird, gibt es abh&auml;ngig von der verwendeten AX-Version verschiedene Ans&auml;tze. In den beiden Beispielen wird ermittelt, ob die Dimension Palettennummer aktiv ist:
</p>

<p><strong>Dynamics AX 2009</strong>
</p>

<div style="padding: 5px; width: 460px; height: 60px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">inventDimSetup::find(inventTable::find(_itemId).DimGroupId, <br />
&nbsp;&nbsp;&nbsp; fieldnum(InventDim, wmsPalletId)).Active
</div>

<p><strong>Dynamics AX 2012</strong>
</p>

<div style="padding: 5px; width: 460px; height: 60px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">EcoResDimensionGroupSetup::isInventoryDimensionActiveForItem(<br />
&nbsp;&nbsp;&nbsp; _itemId, fieldNum(InventDim, wmsPalletId))
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Fri, 16 Mar 2012 18:47:00 +0100</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=423</link>
<comments>http://www.schweda.net/blog_ax.php?bid=423</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=423</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=423</wfw:commentRss>
</item>
<item>
<title>Funktion num2expstr</title>
<description><![CDATA[
<p>Vor kurzem lief mir eine Fehlermeldung in Dynamics AX &uuml;ber den Weg die vermuten lies, da&szlig; in einer Tabelle Werte mit mehr Nachkommastellen gespeichert waren, als Dynamics AX dort erwartet h&auml;tte. Leider sieht man &uuml;ber den Table-Browser solche Nachkommastellen oft nicht, deshalb musste ich mir mit einem Job und der Funktion <strong>num2expstr </strong>helfen, letztere zeigt die Werte detailierter als z.B. der Table-Browser an.
</p>

<div style="padding: 5px; width: 460px; height: 180px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void num2expstrTest(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; ledgerTrans ledgerTrans;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; while select ledgerTrans&nbsp;<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(strFmt(&quot;%1&nbsp; %2&quot;, num2expstr(ledgerTrans.AmountMST), <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ledgerTrans.AmountMST));<br />
&nbsp;&nbsp;&nbsp; }<br />
}
</div>

<p>&nbsp;
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Sat, 10 Mar 2012 19:32:00 +0100</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=413</link>
<comments>http://www.schweda.net/blog_ax.php?bid=413</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=413</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=413</wfw:commentRss>
</item>
<item>
<title>AX 2012: Relations, Surrogate Foreign Keys</title>
<description><![CDATA[
<p>Mit dem Release von Dynamics AX 2012 konfrontiert Microsoft den erfahrenen AX-Entwickler mit zahlreichen Neuerungen. Einige davon betreffen das Herstellen von Beziehungen (Relations) zwischen Tabellen.
</p>

<p>Hatte man in AX 2009 noch die M&ouml;glichkeit, die Relations auf einem Extended Datatyp (EDT) festzulegen, so muss dies nun direkt auf den Tabellen erfolgen. Ausserdem sind die Tabellen nun meist so aufgebaut, da&szlig; Relations &uuml;ber die sogenannten Surrogate Foreign Keys erfolgen.<br />
&nbsp;<br />
Als <strong>Surrogate Foreign Key</strong> bezeichnet man ein einzelnes Feld, &uuml;ber das sich ein Datensatz eindeutig identifizieren l&auml;sst. In vielen Datenbanksystemen ist dies eine vom System generierte Nummer die in der jeweiligen Benutzeroberfl&auml;che oft gar nicht angezeigt wird, in AX w&auml;re dies beispielsweise die RecId. Schon in fr&uuml;heren Versionen von Dynamics AX wurde dieses Feld dazu verwendet, Beziehungen zwischen Tabellen herzustellen, mit Dynamics AX 2012 sollen s&auml;mtliche Relations &uuml;ber die RecId abgebildet werden.
</p>


<p>Neben den Surrogate Foreign Keys gibt es die <strong>Natural Foreign Keys</strong>, &uuml;ber&nbsp; die&nbsp; sich ein Datensatz ebenfalls eindeutig identifizieren l&auml;sst, allerdings in einer auch f&uuml;r den Benutzer lesbaren Form. Ausserdem kann ein Natural Foreign Key mehrere Felder beinhalten.<br />
&nbsp;<br />
Da sowohl der SurrogateForeign&nbsp; Key als auch der Natural Foreign Key einen Datensatz eindeutig identifizieren, k&ouml;nnen beide als <strong>Primary Key </strong>verwendet werden. Die neue Eigenschaft <strong>ReplacementKey </strong>von Tabellen steuert die Anzeige im AX-Client, unabh&auml;ngig vom tats&auml;chlichen Primary Key.
</p>

<p>&nbsp;
</p>

<p>Um die Verwendung dieser Keys zu verdeutlichen, m&ouml;chte ich in Dynamics AX 2012 beispielsweise zwei Tabellen erstellen, in welchen Autohersteller und deren Modelle gespeichert werden sollen.
</p>

<p>Die erste Tabelle <em>DmoCarManufacturer </em>enth&auml;lt<em> </em>nur zwei Felder:
</p>

<ul>
    
<li>ManufacturerID (Abgeleitet von einem eigens erstellten EDT vom Typ String mit dem Label Hersteller)
</li>
    
<li>Name (Abgeleitet vom EDT Name)
</li>

</ul>

<p><a href="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_2.jpg" target="_blank"><img width="202" border="0" height="308" src="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_2.jpg" alt="" title="Screenshot" /></a>
</p>

<p>Wenn man sich die Eigenschaften der Tabelle nach der Erstellung ansieht, erkennt man da&szlig; AX die Eigenschaft <em>CreateRecIdIndex </em>auf YES gesetzt und als <em>Primary Key </em>und <em>Clustered Index</em>&nbsp;den Wert <em>SurrogateKey </em>eingetragen hat.
</p>

<p><img border="0" src="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_4.jpg" alt="" />
</p>

<p>Nun erstellt man einen neuen eindeutigen Index &uuml;ber das Feld <em>ManufacturerId </em>und legt diesen &uuml;ber die gleichnamige Eigenschaft als <strong>AlternateKey </strong>fest. <br />
Danach ist dieser Key auf Tabellenebene als <em>ReplacementKey </em>einzustellen wodurch dieses Feld automatisch der FieldGroup <em>AutoIdentification </em>hinzugef&uuml;gt wird.
</p>

<p><img border="0" src="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_5.jpg" alt="" />&nbsp;
</p>

<p>Zus&auml;tzlich habe ich noch die Felder <em>ManufacturerId </em>und <em>Name </em>als <em>TitleFields </em>der Tabelle definiert, dies hat aber f&uuml;r die Relaton selbst keine Auswirkung, lediglich das sp&auml;tere Lookup-Formular wird dadurch benutzerfreundlicher.
</p>

<p>Der n&auml;chste Schritt ist die Erstellung der zweiten Tabelle <em>DmoCarModel</em>.
</p>

<p style="text-align: left;"><a href="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_1.jpg" target="_blank"><img width="457" border="0" height="290" src="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_1.jpg" alt="" title="Screenshot" /></a>
</p>

<p style="text-align: left;">Um nun eine Beziehung zur Tabelle <em>DmoCarManufacturer </em>zu erstellen w&auml;hlt man im Kontextmen&uuml; des Knoten Relations <em>Neue Relation </em>und tr&auml;gt als Tabelle die <em>DmoCarManufacturer </em>ein. Nun kann man &uuml;ber das Kontextmen&uuml; dieser neuen Relation <em>Neu &gt; ForeignKey &gt; PrimaryKey-basiert </em>ausw&auml;hlen. Dadurch erstellt AX ein neues Feld mit dem Namen <em>DmoCarManufacturer</em>, abgeleitet vom EDT <em>RefRecId</em>.
</p>

<p>Das zweite Feld <em>ModelId </em>lege ich manuell an und soll sp&auml;ter die Modellbezeichnung eines Autos beinhalten.
</p>

<p>Um nun die Auswirkung dieser Einstellungen darzustellen, erstelle ich auf Basis der Formular-Vorlage <em>Simple List </em>ein Formular f&uuml;r die Tabelle <em>DmoCarModel </em>und ziehe per Drag &amp; Drop das Feld <em>DmoCarManufacturer </em>in ein Grid des Designs. Dadurch wird innerhalb des Grids eine sogenannte <em>ReferenceGroup </em>erstellt. Auch das zweite Feld der Tabelle <em>ModelId </em>ziehe ich per Drag &amp; Drop ins Grid.
</p>

<p><a href="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_3.jpg" target="_blank"><img border="0" src="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_3.jpg" alt="" title="Screenshot" /></a>&nbsp;
</p>

<p>&Ouml;ffne ich nun dieses Formular und erstelle ich einen neuen Datensatz, sieht man da&szlig; im Lookup des Feldes <em>DmoCarManufacturer </em>nicht die <em>RecId </em>- welche ja in der Datenbank gespeichert wird - angezeigt wird, sondern die sprechenden Felder <em>Hersteller </em>und <em>Name</em>.
</p>

<p><a href="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_6.jpg" target="_blank"><img width="465" border="0" height="375" src="http://www.schweda.net/pictures/blogpics/tb_ax2012_dmocar_6.jpg" alt="" title="Screenshot" /></a>&nbsp;
</p>

<p>&Ouml;ffnet man hingegen die Tabelle <em>DmoCarModel </em>&uuml;ber den TableBrowser, wird der Lookup das Feldes <em>DmoCarManufacturer </em>insoferne etwas anders dargestellt, als da&szlig; man hier auch die <em>RecId </em>sieht.
</p>

<p><a href="http://www.schweda.net/pictures/blogpics/ax2012_dmocar_7.jpg" target="_blank"><img width="465" border="0" height="376" src="http://www.schweda.net/pictures/blogpics/tb_ax2012_dmocar_7.jpg" alt="" title="Screenshot" /></a>&nbsp;
</p>

<p>Informationen dazu sind nat&uuml;rlich&nbsp;in der MSDN (<a href="http://msdn.microsoft.com/en-us/library/aa556809.aspx">http://msdn.microsoft.com/en-us/library/aa556809.aspx</a>) zu finden.&nbsp;
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Fri, 02 Mar 2012 17:39:00 +0100</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=421</link>
<comments>http://www.schweda.net/blog_ax.php?bid=421</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=421</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=421</wfw:commentRss>
</item>
<item>
<title>AX 2012: Eigene Lookups mit Hilfe der Klasse SysLookupMultiSelectCtrl erstellen</title>
<description><![CDATA[
<p>In AX 2012 gibt es &uuml;ber die Klasse <strong>SysLookupMultiSelectCtrl </strong>eine neue M&ouml;glichkeit, um bei einem Formularfeld, welches weder an eine DataSource noch an einen Extended Datatyp gebunden ist, dem Benutzer ein Lookup-Formular anzubieten.
</p>

<p>Diese Klasse hat gegen&uuml;ber der Klasse <strong>SysTableLookup</strong>, die es schon in Dynamics AX 2009 gegeben hat, sowohl einige Vorteile aber&nbsp;auch ein paar Nachteile:
</p>

<p><strong>Vorteile</strong>
</p>

<ul>
    
<li>Aufruf aus der <em>init</em>-Methode eines Formulares aus m&ouml;glich (d.h. es muss die <em>lookup</em>-Methode des jeweiligen Feldes nicht &uuml;berschrieben werden)
</li>
    
<li>Mehrfachauswahl von Werten ist m&ouml;glich
</li>

</ul>

<p><strong>Nachteile</strong>
</p>

<ul>
    
<li>Es k&ouml;nnen keine (Display-)Methoden in den Lookup eingebunden werden
</li>
    
<li>Man muss den Lookup verwenden um einen Wert auszuw&auml;hlen, eine &quot;freie&quot; Eingabe ist nicht m&ouml;glich
</li>

</ul>


<p>Hier ein einfaches Anwendungsbeispiel:
</p>

<p>Es soll bei dem FormStringControl namens <em>LookupStingEdit </em>eine Lookup-M&ouml;glichkeit auf die Debitorengruppen geschaffen werden. Es sollen aber nur bestimmte Gruppen angezeigt werden (realisiert &uuml;ber einen QueryBuildRange auf&nbsp;einen Query) und es soll der Name der Debitorengruppe retourniert werden (realisiert &uuml;ber den 5 Parameter der Methode <em>SysLookupMultiSelectCtrl::constructWithQuery</em>).
</p>

<div style="padding: 5px; width: 460px; height: 160px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public void init()<br />
{<br />
&nbsp;&nbsp;&nbsp; Query query;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; super();<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; query = new query();<br />
&nbsp;&nbsp;&nbsp; query.addDataSource(tableNum(CustGroup));<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; SysQuery::findOrCreateRange(query.dataSourceTable(tableNum(CustGroup)), fieldNum(CustGroup, Name)).value(&quot;*inter*&quot;);<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; SysLookupMultiSelectCtrl::constructWithQuery(this, LookupStringEdit, query, false, [tableNum(CustGroup), fieldNum(CustGroup, Name)]);<br />
}
</div>

<p><a href="http://www.schweda.net/pictures/blogpics/ax2012_SysLookupMultiSelectCtrl_1.jpg" target="_blank"><img width="465" border="0" height="157" src="http://www.schweda.net/pictures/blogpics/tb_ax2012_SysLookupMultiSelectCtrl_1.jpg" alt="" title="Screenshot" /></a>
</p>

<p>Diese&nbsp;neue Klasse&nbsp;kann man auch f&uuml;r Dialog-Felder verwenden, beispielsweise innerhalb eines Jobs:
</p>

<div style="padding: 5px; width: 460px; height: 160px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void dialogAddCustomLookup(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; Dialog dialog;<br />
&nbsp;&nbsp;&nbsp; DialogField dialogField;<br />
&nbsp;&nbsp;&nbsp; Query query;<br />
&nbsp;&nbsp;&nbsp; ;<br />
&nbsp;&nbsp;&nbsp; // Build dialog&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; dialog = new Dialog();&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; dialogField = dialog.addField((&quot;name&quot;));<br />
<br />
&nbsp;&nbsp;&nbsp; // Build query for lookup<br />
&nbsp;&nbsp;&nbsp; query = new Query();<br />
&nbsp;&nbsp;&nbsp; query.addDataSource(tableNum(CustGroup));<br />
&nbsp;&nbsp;&nbsp; SysQuery::findOrCreateRange(query.dataSourceTable(tableNum(CustGroup)), fieldNum(CustGroup, Name)).value(&quot;*inter*&quot;);<br />
<br />
&nbsp;&nbsp;&nbsp; // Run dialog<br />
&nbsp;&nbsp;&nbsp; dialog.run(true);<br />
<br />
&nbsp;&nbsp;&nbsp; // Add lookup to dialogfield<br />
&nbsp;&nbsp;&nbsp; SysLookupMultiSelectCtrl::constructWithQuery(dialog.formRun(), dialogField.control(), query, false, [tableNum(CustGroup), fieldNum(CustGroup, Name)]);<br />
<br />
&nbsp;&nbsp;&nbsp; dialog.wait();<br />
<br />
&nbsp;&nbsp;&nbsp; // Get values from dialog<br />
&nbsp;&nbsp;&nbsp; if(dialog.closedOk())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(dialogField.value());<br />
}
</div>

<p>F&uuml;hrt man den Job aus, &ouml;ffnet sich der Dialog wie folgt:
</p>

<p><a href="http://www.schweda.net/pictures/blogpics/ax2012_SysLookupMultiSelectCtrl_1.jpg" target="_blank"><img width="305" border="0" height="170" src="http://www.schweda.net/pictures/blogpics/ax2012_SysLookupMultiSelectCtrl_3.jpg" alt="" title="Screenshot" /></a>
</p>

<p>Auch innerhalb einer von <em>RunBasebatch </em>abgeleiteten Klasse kann der Dialog um einen Lookup erweitert werden. Daf&uuml;r m&uuml;ssen die Methoden <em>dialog </em>und <em>dialogPostRun </em>angepasst werden. Im Beispiel wird ein Lookup auf die Debitoren erm&ouml;glicht, wobei auch Informationen aus der jeweiligen Debitorengruppe angezeigt werden:
</p>

<div style="padding: 5px; width: 460px; height: 160px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public Object dialog()<br />
{<br />
&nbsp;&nbsp;&nbsp; DialogRunbase&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dialog = super();<br />
&nbsp;&nbsp;&nbsp; queryBuildDataSource qbds;<br />
&nbsp;&nbsp;&nbsp; #resAppl<br />
&nbsp;&nbsp;&nbsp; ;<br />
&nbsp;&nbsp;&nbsp; dialogField = dialog.addField((&quot;name&quot;));<br />
<br />
&nbsp;&nbsp;&nbsp; // Build query for lookup<br />
&nbsp;&nbsp;&nbsp; query = new Query();<br />
&nbsp;&nbsp;&nbsp; qbds = query.addDataSource(tableNum(custTable));<br />
&nbsp;&nbsp;&nbsp; qbds.fields().clearFieldList();<br />
&nbsp;&nbsp;&nbsp; qbds.addSelectionField(fieldNum(CustTable, AccountNum));<br />
&nbsp;&nbsp;&nbsp; qbds.addSelectionField(fieldNum(CustTable, segmentId));<br />
&nbsp;&nbsp;&nbsp; qbds = qbds.addDataSource(tableNum(custGroup));<br />
&nbsp;&nbsp;&nbsp; qbds.fields().clearFieldList();<br />
&nbsp;&nbsp;&nbsp; qbds.addSelectionField(fieldNum(CustGroup, CustGroup));<br />
&nbsp;&nbsp;&nbsp; qbds.addSelectionField(fieldNum(CustGroup, name));<br />
&nbsp;&nbsp;&nbsp; qbds.joinMode(JoinMode::InnerJoin);<br />
&nbsp;&nbsp;&nbsp; qbds.relations(true);<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; SysQuery::findOrCreateRange(query.dataSourceTable(tableNum(CustGroup)), fieldNum(CustGroup, Name)).value(&quot;*inter*&quot;);<br />
<br />
&nbsp;&nbsp;&nbsp; return dialog;<br />
}
</div>

<p>&nbsp;
</p>

<div style="padding: 5px; width: 460px; height: 140px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public void dialogPostRun(DialogRunbase dialog)<br />
{<br />
&nbsp;&nbsp;&nbsp; ;<br />
&nbsp;&nbsp;&nbsp; // Add lookup to dialogfield<br />
&nbsp;&nbsp;&nbsp; SysLookupMultiSelectCtrl::constructWithQuery(dialog.formRun(), dialogField.control(), query, false, [tableNum(custTable), fieldNum(custTable, segmentId)]); <br />
<br />
&nbsp;&nbsp;&nbsp; super(dialog);<br />
}
</div>

<p><a href="http://www.schweda.net/pictures/blogpics/ax2012_SysLookupMultiSelectCtrl_2.jpg" target="_blank"><img width="465" border="0" height="234" src="http://www.schweda.net/pictures/blogpics/tb_ax2012_SysLookupMultiSelectCtrl_2.jpg" alt="" title="Screenshot" /></a>
</p>

<p><strong>Hinweis</strong>: Wenn innerhalb des Lookups mehrere Tabellen verjoint werden, k&ouml;nnen nur Werte aus der &quot;Haupttabelle&quot; des Queries retourniert werden. Wichtig ist weiters, da&szlig; nur jene Felder der Tabelle retourniert werden k&ouml;nnen, die auch im Lookup angezeigt werden.
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Tue, 21 Feb 2012 19:19:00 +0100</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=419</link>
<comments>http://www.schweda.net/blog_ax.php?bid=419</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=419</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=419</wfw:commentRss>
</item>
<item>
<title>Eigenes Lookup-Formular mit Hilfe der Klasse SysTableLookup gestalten</title>
<description><![CDATA[
<p>Ab und an kommt man als Entwickler in die Verlegenheit, ein Formularfeld, welches weder an eine Datenquelle (DataSource) oder einen Extended Datatyp gebunden ist, um ein Lookup-Formular zu erweitern. Daf&uuml;r stellt Dynamics AX die Klasse <strong>SysTableLookup </strong>zur Seite, die man in die <em>lookup</em>-Methode des jeweiligen Feldes einbinden kann.
</p>

<p>Hier ein einfaches Beispiel unter Verwendung eines Queries, bei dem prinzipiell ein Lookup auf die Kundengruppen m&ouml;glich sein soll, aber nur bestimmte angezeigt werden sollen. Diese Einschr&auml;nkung kann &uuml;ber <em>sysQuery::findOrCreateRange</em> abgebildet werden.
</p>

<p>Das Beispiel funktioniert &uuml;brigens sowohl in Dynamics AX 2009 als auch AX 2012.
</p>

<div style="padding: 5px; width: 460px; height: 160px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public void lookup()<br />
{<br />
&nbsp;&nbsp;&nbsp; sysTableLookup sysTableLookup;<br />
&nbsp;&nbsp;&nbsp; query query;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; super();<br />
<br />
&nbsp;&nbsp;&nbsp; query = new query();<br />
&nbsp;&nbsp;&nbsp; query.addDataSource(tableNum(custGroup));<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; sysQuery::findOrCreateRange(query.dataSourceTable(tableNum(custGroup)), fieldNum(custGroup, name)).value(&quot;*inter*&quot;);<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; sysTableLookup = sysTableLookup::newParameters(tableNum(custGroup), this);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.parmQuery(query);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupfield(fieldNum(custGroup, custGroup));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupfield(fieldNum(custGroup, name));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.performFormLookup();<br />
}
</div>


<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax_SysTableLookup_6.jpg"><img width="297" height="103" title="Screenshot" alt="" border="0" src="http://www.schweda.net/pictures/blogpics/ax_SysTableLookup_6.jpg" /></a>
</p>

<p>Im n&auml;chsten Beispiel sollen nur Kundengruppen angezeigt werden, wo es auch Kunden/Debitoren dazu gibt, dies wurde &uuml;ber einen <em>ExistsJoin </em>mit der Tabelle <em>CustTable </em>realisiert.
</p>

<p>Weiteres werden die im Lookup angezeigten Spalten die Labels &uuml;ber die Methode <em>setLabel </em>ge&auml;ndert und es wird nicht - wie es standardm&auml;ssig der Fall ist - die erste Spalte als zu retournierender Wert angegeben sondern die Spalte mit dem Namen der Kundengruppe (daf&uuml;r wird der zweite, boolsche Parameter der Methode <em>addLookupfield </em>verwendet):
</p>

<div style="padding: 5px; width: 460px; height: 160px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public void lookup()<br />
{<br />
&nbsp;&nbsp;&nbsp; sysTableLookup sysTableLookup;<br />
&nbsp;&nbsp;&nbsp; query query;<br />
&nbsp;&nbsp;&nbsp; queryBuildDataSource qbds_custGroup;<br />
&nbsp;&nbsp;&nbsp; queryBuildDataSource qbds_custTable;<br />
<br />
&nbsp;&nbsp;&nbsp; super();<br />
<br />
&nbsp;&nbsp;&nbsp; query = new query();<br />
&nbsp;&nbsp;&nbsp; qbds_custGroup = query.addDataSource(tableNum(custGroup));<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; qbds_custTable = qbds_custGroup.addDataSource(tableNum(custTable));<br />
&nbsp;&nbsp;&nbsp; qbds_custTable.joinMode(joinMode::ExistsJoin);<br />
&nbsp;&nbsp;&nbsp; qbds_custTable.relations(true);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup = sysTableLookup::newParameters(tableNum(CustGroup), this);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.parmQuery(query);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupfield(fieldNum(custGroup, custGroup));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.setLabel(&quot;Custgroup ID&quot;);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupfield(fieldNum(custGroup, name), true);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.setLabel(&quot;Name of custgroup&quot;);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.performFormLookup();<br />
}
</div>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax_SysTableLookup_5.jpg"><img width="297" height="188" title="Screenshot" alt="" border="0" src="http://www.schweda.net/pictures/blogpics/ax_SysTableLookup_5.jpg" /></a>
</p>

<p>Auch dieses Beispiel funktioniert sowohl in Dynamics AX 2009 als auch AX 2012.
</p>

<p>Zus&auml;tzlich zu den oben beschriebenen M&ouml;glichkeiten k&ouml;nnen auch <strong>Display-Methoden</strong> von Tabellen eingebunden werden. Wichtig dabei ist lediglich, da&szlig; s&auml;mtliche Felder, die von der anzuzeigenden Display-Methode ben&ouml;tigt werden, auch im Lookup angezeigt werden. Im Beispiel wird die Methode <em>bankAccountNum </em>eingebunden, diese ben&ouml;tigt die Werte aus den Feldern <em>accountNum </em>und <em>bankAccount </em>der Tabelle <em>custTable</em>:
</p>

<div style="padding: 5px; width: 460px; height: 160px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public void lookup()<br />
{<br />
&nbsp;&nbsp;&nbsp; sysTableLookup sysTableLookup;<br />
<br />
&nbsp;&nbsp;&nbsp; super();<br />
<br />
&nbsp;&nbsp;&nbsp; sysTableLookup = sysTableLookup::newParameters(tableNum(custTable), this, true);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupfield(fieldNum(custTable, accountNum));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupMethod(tableMethodStr(custTable, name));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupfield(fieldNum(custTable, bankaccount));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupMethod(tableMethodStr(custTable, bankAccountNum));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.performFormLookup();<br />
}
</div>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax_SysTableLookup_4.jpg"><img width="465" height="187" title="Screenshot" alt="" border="0" src="http://www.schweda.net/pictures/blogpics/tb_ax_SysTableLookup_4.jpg" /></a>
</p>

<p>Im folgenden Beispiel gehe ich noch einen Schritt weiter und bef&uuml;lle zuerst eine <strong>tempor&auml;re Tabelle</strong>, aus der anschlie&szlig;end die Daten angezeigt werden. Ganz konkret werden s&auml;mtliche Kundengruppen inkl. einer Anzahl der zugewiesenen Kunden.
</p>

<p><em>Notiz:</em>Als tempor&auml;re Tabelle habe ich im Beispiel die <em>TmpJobSelect </em>verwendet, sch&ouml;ner w&auml;re nat&uuml;rlich eine eigene Tabelle. Auch bin ich mir dar&uuml;ber im klaren, da&szlig; das kontruierte Beispiel auch ohne tempor&auml;re Tabelle l&ouml;sbar gewesen w&auml;re.
</p>

<div style="padding: 5px; width: 460px; height: 160px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public void lookup()<br />
{<br />
&nbsp;&nbsp;&nbsp; sysTableLookup sysTableLookup;<br />
&nbsp;&nbsp;&nbsp; query query;<br />
&nbsp;&nbsp;&nbsp; TmpJobSelect TmpJobSelect;<br />
&nbsp;&nbsp;&nbsp; custGroup custGroup;<br />
<br />
&nbsp;&nbsp;&nbsp; super();<br />
<br />
&nbsp;&nbsp;&nbsp; // Fill temp-table&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; while select custGroup<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpJobSelect.ClassName = custGroup.CustGroup;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpJobSelect.ClassDescription = custGroup.name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpJobSelect.id = (select count(recId) from CustTable where custtable.CustGroup == custGroup.CustGroup).recid;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TmpJobSelect.insert();<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; query = new query();<br />
&nbsp;&nbsp;&nbsp; query.addDataSource(tableNum(TmpJobSelect));<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; sysTableLookup = sysTableLookup::newParameters(tableNum(TmpJobSelect), this);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.parmTmpBuffer(TmpJobSelect);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.parmQuery(query);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupfield(fieldNum(TmpJobSelect, ClassName));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.setLabel(&quot;Custgroup&quot;);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupfield(fieldNum(TmpJobSelect, ClassDescription));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.setLabel(&quot;Name&quot;);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.addLookupfield(fieldNum(TmpJobSelect, id));<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.setLabel(&quot;Count of customers&quot;);<br />
&nbsp;&nbsp;&nbsp; sysTableLookup.performFormLookup();<br />
}
</div>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax_SysTableLookup_7.jpg"><img width="389" height="212" title="Screenshot" alt="" border="0" src="http://www.schweda.net/pictures/blogpics/ax_SysTableLookup_7.jpg" /></a>
</p>

<p>Auch dieses Beispiel funktioniert sowohl in Dynamics AX 2009 als auch AX 2012.
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Mon, 20 Feb 2012 14:23:00 +0100</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=420</link>
<comments>http://www.schweda.net/blog_ax.php?bid=420</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=420</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=420</wfw:commentRss>
</item>
<item>
<title>Windows 7: Als anderer Benutzer ausführen</title>
<description><![CDATA[
<p>Als Entwickler muss ich Dynamics AX immer wieder mal mit einem anderen Windows-Login starten, als dem eigenen. Deshalb habe ich in Windows 7 die Option <strong>Als anderer Benutzer ausf&uuml;hren</strong> im Kontext-Men&uuml; schmerzlich vermisst und statt dessen&nbsp; immer <a title="Dynamics AX mit einem bestimmten Windowslogin starten" target="_self" href="http://www.schweda.net/blog_ax.php?nid=runas1">Batch-Dateien</a> daf&uuml;r verwendet.
</p>

<p>&Uuml;ber einen Blog-Eintrag bin ich aber auf einen wertvollen Tip gestossen: Wenn man die [SHIFT]-Taste h&auml;lt, w&auml;hrend man &uuml;ber die rechte Maustaste das Kontext-Men&uuml; einer Applikation aufruft, steht die Option <strong>Als anderer Benutzer ausf&uuml;hren</strong> wieder zur Verf&uuml;gung.
</p>

<p><img border="0" align="left" width="334" height="161" title="Als anderer Benutzer ausf&uuml;hren" alt="Als anderer Benutzer ausf&uuml;hren" src="http://www.schweda.net/pictures/blogpics/dynamics_ax_runas_shift.jpg" />
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Fri, 02 Dec 2011 23:01:00 +0100</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=418</link>
<comments>http://www.schweda.net/blog_ax.php?bid=418</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=418</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=418</wfw:commentRss>
</item>
<item>
<title>AX 2012: Einen Bericht mit den SQL Reporting Services erstellen</title>
<description><![CDATA[
<p>Mit der Version Dynamics AX 2012 halten die SQL Reporting Services (SSRS) nun endg&uuml;ltig Einzug im Leben eines jeden AX-Entwicklers. Zeit also, sich mit diesem Thema etwas intensiver zu besch&auml;ftigen. Die Ergebnisse meiner ersten Gehversuche mit den SSRS pr&auml;sentiere ich Euch nun in diesem Beitrag.
</p>

<p>Szenario: Es soll ein Bericht erstellt werden, bei welchem der Umsatz pro Verkaufsgruppe ausgewertet werden kann.
</p>

<p>&nbsp;
</p>

<h2>Schritt 1: Erstellen eines Queries in Dynamics AX
</h2>

<table width="100%" cellspacing="1" cellpadding="1" border="0">
    <tbody>
        <tr>
            
<td valign="top" align="left">Ich gehe davon aus, da&szlig; der geneigte Leser schon einmal einen Query  erstellt hat, deshalb werde ich darauf nur sehr oberfl&auml;chlich eingehen.<br />
            <br />
            Basis-Tabellen meines Queries sind die Tabellen<br />
            
<ul>
                
<li>CustInvoiceTrans
</li>
                
<li>CustInvoiceJour
</li>
                
<li>CommissionSalesGroup
</li>
            
</ul>
            
<p>Die Tabelle <em>CustInvoiceTrans </em>wird per InnerJoin mit der <em>CustInvoiceJour </em>&uuml;ber die im Screenshot gezeigten Felder verkn&uuml;pft, die Tabelle <em>CommissionSalesGroup </em>wird per OuterJoin &uuml;ber das Feld <em>SalesGroup </em>verkn&uuml;pft.
</p>
            
</td>
            
<td valign="top">&nbsp;
</td>
            
<td valign="top" style="text-align: right;"><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax_query.jpg"><img width="232" align="right" height="179" title="Query" alt="Query" src="http://www.schweda.net/pictures/blogpics/ax_query_small.jpg" /></a>
</td>
        </tr>
    </tbody>

</table>

<p>Seit AX 2012 muss die Eigenschaft <em>Dynamic</em> der Fields-Gruppe aller beteiligten Tabellen entsprechend gesetzt werden, im einfachsten Fall wird diese auf <em>Yes </em>gesetzt, um im Visual Studio sp&auml;ter alle Felder der Tabellen verwenden zu k&ouml;nnen.
</p>


<p>&nbsp;
</p>

<h2>Schritt 2: Erstellen eines Projektes im Visual Studio
</h2>

<table width="100%" cellspacing="1" cellpadding="1" border="0">
    <tbody>
        <tr>
            
<td valign="top">&Uuml;ber <em>File &gt; New &gt; Project</em> das Template Microsoft Dynamics AX  ausw&auml;hlen, Report Model ausw&auml;hlen und einen Namen und Speicherort  angeben.
</td>
            
<td valign="top">&nbsp;
</td>
            
<td valign="top"><a target="_blank" href="http://www.schweda.net/pictures/blogpics/vs_solutionexplorer_project.jpg"><img width="216" height="115" title="Solution Explorer" alt="Solution Explorer" src="http://www.schweda.net/pictures/blogpics/vs_solutionexplorer_project_small.jpg" /></a>
</td>
        </tr>
    </tbody>

</table>

<p>&nbsp;
</p>

<h2>Schritt 3: Erzeugen eines DataSets
</h2>

<table width="100%" cellspacing="1" cellpadding="1" border="0">
    <tbody>
        <tr>
            
<td><a target="_blank" href="http://www.schweda.net/pictures/blogpics/vs_dataset_fields.jpg"><img width="191" height="316" title="DataSet" alt="DataSet" src="http://www.schweda.net/pictures/blogpics/vs_dataset_fields_small.jpg" /></a>
</td>
            
<td>
            
<p>Innerhalb dieses Reports ist nun ein neues DataSet zu erstellen.  Diesem geben wir den Namen <strong>CustInvoiceDataSet </strong>und tragen als Query den  zuvor in Dynamics AX erstellten ein. Letzteres erfolgt &uuml;ber einen Dialog  wo auch jene Felder oder Methoden gew&auml;hlt werden k&ouml;nnen, die im Bericht  ausgegeben werden sollen.
</p>
            
<p>In unserem Fall sind dies:
</p>
            
<p>Aus der Tabelle <em>CustInvoiceTrans </em>die Felder
</p>
            
<ul>
                
<li>InvocieId
</li>
                
<li>InvocieDate
</li>
                
<li>ItemId
</li>
                
<li>SalesGroup
</li>
                
<li>LineAmountMST
</li>
            
</ul>
            
<p>und die Methode
</p>
            
<ul>
                
<li>itemName()
</li>
            
</ul>
            
<p>Aus der Tabelle <em>CommissionSalesGroup</em> ben&ouml;tige ich das Feld
</p>
            
<ul>
                
<li>Name
</li>
            
</ul>
            
<p>Gleichzeitig habe ich das DataSet &uuml;ber die Properties auf <strong>CustInvoiceDataSet </strong>umbenannt.
</p>
            
</td>
        </tr>
    </tbody>

</table>

<p>Die Eigenschaften des DataSet stellen sich nach Abschlu&szlig; des Dialoges wie folgt dar:
</p>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/vs_dataset_properties.jpg"><img width="465" height="177" title="DataSet Properties" alt="DataSet Properties" src="http://www.schweda.net/pictures/blogpics/vs_dataset_properties_small.jpg" /></a>
</p>

<p>&nbsp;
</p>

<h2>Schritt 4: Erzeugen eines Designs
</h2>

<p>Nun kann das DataSet per Drag &amp; Drop in den Knoten <strong>Designs </strong>gezogen werden. Dadurch wird ein neues Design namens <strong>AutoDesign1 </strong>erstellt.
</p>

<p>Nun gilt es einige Eigenschaften dieses Designs anzupassen. Dazu z&auml;hlen das Seitenformat, Bezeichnungen (<em>Title</em>) des Berichtes aber auch das Layout (<em>LayoutTemplate</em>), im Beispiel habe ich als Seitenformat die Einstellungen f&uuml;r DIN-A4 eingetragen.
</p>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/vs_design_properties.jpg"><img width="465" height="263" title="Properties" alt="Properties" src="http://www.schweda.net/pictures/blogpics/vs_design_properties_small.jpg" /></a>&nbsp;
</p>

<p>Der automatisch generierten Tabelle <strong>CustInvoiceDataSetTable </strong>weisen wir ebenfalls &uuml;ber die Eigenschaft <em>StyleTemplate </em>ein Layout zu. Im Beispiel habe ich das Layout so gew&auml;hlt, da&szlig; die einzelnen Zeilen sp&auml;ter abwechselnd grau oder wei&szlig; unterlegt werden.
</p>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/vs_design_dataset_properties.jpg"><img width="465" height="327" alt="" src="http://www.schweda.net/pictures/blogpics/vs_design_dataset_properties_small.jpg" /></a>
</p>

<p>&nbsp;
</p>

<h2>Schritt 5:Gruppierung einrichten
</h2>

<table width="100%" cellspacing="1" cellpadding="1" border="0">
    <tbody>
        <tr>
            
<td><a href="http://www.schweda.net/pictures/blogpics/vs_design_groupings.jpg" target="_blank"><img width="213" height="400" src="http://www.schweda.net/pictures/blogpics/vs_design_groupings_small.jpg" alt="Gruppierung" title="Gruppierung" /></a>
</td>
            
<td valign="top" align="left">Nun gilt es, die geforderte Gruppierung nach der Verkaufsgruppe (Feld <em> SalesGroup</em>) abzubilden. Hierzu muss im Knoten Groupings der <strong> CustInvoiceDataSetTable</strong> benannten Tabelle ein neuer Knoten erstellt  werden. Diesen nennen wir <strong>SalesGroupGrouping </strong>und vergeben im einen  sprechenden Label, z.B. Verkaufsgruppe.<br />
            <br />
            In diesem Knoten k&ouml;nnen wir nun einen Unterknoten erstellen, in  dessen Expression wir das Feld <em>SalesGroup </em>eintragen. Dieser Knoten  bekommt nun noch den Namen <strong>SalesGroup</strong>.<br />
            <br />
            Danach erstellen wir jeweils einen neuen Knoten im Header und  Footer-Bereich. Auch diese bekommen einen m&ouml;glichst selbstsprechenden  Namen (<strong>SalesGroupHeader </strong>bzw. <strong>SalesGroupFooter</strong>).<br />
            <br />
            Im <strong>SalesGroupHeader </strong>erzeugen wir zwei Unterknoten. Beim Ersten tragen  wir in der Eigenschaft <em>Expression </em>das Feld <em>SalesGroup</em> ein, beim Zweiten  das Feld <em>Name</em>.
</td>
        </tr>
    </tbody>

</table>

<p>Im <strong>SalesGroupFooter </strong>erzeugen wie nun in Summe sieben Unterknoten. Nur beim siebenten tragen wir &uuml;ber die Eigenschaft <em>Expression </em>einen Wert ein, die anderen taufen wir <strong>Dummy1 </strong>bis <strong>Dummy6</strong>.
</p>

<p><a href="http://www.schweda.net/pictures/blogpics/vs_data_dummy_properties.jpg" target="_blank"><img width="465" height="177" src="http://www.schweda.net/pictures/blogpics/vs_data_dummy_properties_small.jpg" alt="Properties" title="Properties" /></a>
</p>

<p>Damit diese Summe je Verkaufsgruppe korrekt formatiert wird, passen wir die Eigenschaften entsprechend an:
</p>

<p><a href="http://www.schweda.net/pictures/blogpics/vs_groupsum_properties.jpg" target="_blank"><img width="465" height="252" src="http://www.schweda.net/pictures/blogpics/vs_groupsum_properties_small.jpg" alt="Properties" title="Properties" /></a>
</p>

<p>Hintergrund der Dummy-Felder ist, da&szlig; Visual-Studio die Spalten im Footer automatisch unter den Spalten im Data-Bereich versucht auszurichten. W&uuml;rden wir diese Dummy-Felder nicht erstellen, w&uuml;rde die Summe unterhalb der ersten Spalte&nbsp; angedruckt.
</p>

<p>In fr&uuml;heren Versionen von Dynamics AX h&auml;tten wir einfach die Eigenschaft <em>ModelFieldName </em>f&uuml;r solcherart Positionierung herangezogen, eine solche Eigenschaft scheint es aber in Visual Studio nicht zu geben.
</p>

<p>&nbsp;
</p>

<h2>Schritt 6: Reihenfolge der Spalten und Detail-Eigenschaften anpassen
</h2>

<p><a href="http://www.schweda.net/pictures/blogpics/vs_sorting_salesgroup_properties.jpg" target="_blank"><img width="465" height="118" src="http://www.schweda.net/pictures/blogpics/vs_sorting_salesgroup_properties_small.jpg" alt="Properties" title="Properties" /></a>
</p>

<p>Damit die Daten in einer bestimmten Reihenfolge sortiert angedruckt werden, erstellen wir im Sorting-Knoten entsprechende Unterknoten und tragen &uuml;ber deren Eigenschaft <em>SortBy </em>das jeweilige Feld ein. Wir sortieren nach Verkaufsgruppe, Rechnungsnummer und Rechnungsdatum.
</p>

<p>Abschlie&szlig;end pr&uuml;fen bzw. &auml;ndern wir die Reihenfolge der anzudruckenden Felder im Data-Bereich und passen &uuml;ber die jeweiligen Eigenschaften Spaltenbreiten und ggf. die Bezeichnungen an. So w&auml;hle ich zum Beispiel f&uuml;r die Spalte <em>LineAmountMST </em>als Bezeichnung <em>Betrag </em>statt dem vom Visual Studio vorgeschlagenen Label.
</p>

<p>&nbsp;
</p>

<h2>Schritt 7: Spalte Betrag einf&auml;rben
</h2>

<p>Damit Gutschriften bzw. Rechnungen mit negativen Werten rot dargestellt  werden, &auml;ndern wir die Eigenschaft <em>Style &gt; Font &gt; Color</em> &uuml;ber eine  entsprechende Expression:
</p>

<p><a href="http://www.schweda.net/pictures/blogpics/vs_data_lineamountmst_fontcolor_expression.jpg" target="_blank"><img width="465" height="377" src="http://www.schweda.net/pictures/blogpics/vs_data_lineamountmst_fontcolor_expression_small.jpg" alt="Expression" title="Expression" /></a>&nbsp;
</p>

<p>Diese &Auml;nderung bewirkt, da&szlig; im Bericht negative Betr&auml;ge sp&auml;ter wie folgt dargestellt werden:
</p>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax_report_colored_lines.jpg"><img width="465" height="52" title="Bericht mit eingef&auml;rbten Werten" alt="Bericht mit eingef&auml;rbten Werten" src="http://www.schweda.net/pictures/blogpics/ax_report_colored_lines_small.jpg" /></a>
</p>

<p>&nbsp;
</p>

<h2>Schritt 8: MenuItem in Dynamics AX erzeugen
</h2>

<table width="100%" cellspacing="1" cellpadding="1" border="0">
    <tbody>
        <tr>
            
<td valign="top">Abschlie&szlig;end erstellen wir in Dynamics AX ein neues MenuItem, verkn&uuml;pfen  dieses mit einem Men&uuml; um den Bericht aus Dynamics AX heraus starten zu k&ouml;nnen.<br />
            <br />
            AX erzeugt - wie schon in fr&uuml;heren Versionen - automatisch einen  Dialog, wo man die anzuzeigenden Daten filtern kann.
</td>
            
<td>&nbsp;
</td>
            
<td><a href="http://www.schweda.net/pictures/blogpics/ax_menuitem.jpg" target="_blank"><img width="232" height="118" src="http://www.schweda.net/pictures/blogpics/ax_menuitem_small.jpg" alt="Menuitem" title="Menuitem" /></a>
</td>
        </tr>
    </tbody>

</table>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax_dialog.jpg"><img title="Dialog" alt="Dialog" src="http://www.schweda.net/pictures/blogpics/ax_dialog_small.jpg" /></a>&nbsp;
</p>

<p>&nbsp;
</p>

<h2>Schritt 9: Aufrufen des Berichtes aus Dynamics AX heraus - Fertig
</h2>

<p><a target="_blank" href="http://www.schweda.net/pictures/blogpics/ax_report_examplepage.jpg"><img width="465" height="266" title="Bericht" alt="Bericht" src="http://www.schweda.net/pictures/blogpics/ax_report_examplepage_small.jpg" /></a>&nbsp;
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Fri, 04 Nov 2011 19:06:00 +0100</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=417</link>
<comments>http://www.schweda.net/blog_ax.php?bid=417</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=417</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=417</wfw:commentRss>
</item>
<item>
<title>SID für einen Active-Directory-User auslesen</title>
<description><![CDATA[
<p>Wer schon einmal eine Applikation inkl. Datenbank von einer Netzwerk-Dom&auml;ne in eine andere &uuml;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&auml;lt die Fehlermeldung:
</p>

<blockquote>

<p>You are not recognized user of Dynamics AX. Please contact your system administrator
</p>

</blockquote>

<p>Die Ursache daf&uuml;r ist, da&szlig; in der Tabelle <strong>UserInfo </strong>- das ist jene Tabelle wo die AD-Benutzer verwaltet werden - nat&uuml;rlich noch die Benutzer der Ursprungsdom&auml;ne hinterlegt sind. Im einfachsten Fall &auml;ndert man in dieser Tabelle den Eintrag f&uuml;r den Administrator, indem man die Felder <em>NetworkDomain</em>, <em>NetworkAlias </em>und <em>SID </em>entsprechend &auml;ndert. <em>NetworkDomain </em>und <em>NetworkAlias </em>sind selbsterkl&auml;rend, woher bekommt man aber die <em>SID</em>?
</p>

<p>Eine einfache Internet-Recherche nach &quot;GET SID&quot; liefert einige M&ouml;glichkeiten, weniger bekannt ist aber, da&szlig; auch Dynamics AX 2009 selbst eine Methode zur Verf&uuml;gung stellt, um die SID f&uuml;r einen Benutzer auszulesen.
</p>

<p>Jetzt braucht man also nur noch ein anderes, bereits lauff&auml;higes AX, wo man sich anmelden und den Job absetzen kann ;-)
</p>

<div style="padding: 5px; width: 460px; height: 100px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void getUserSid(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; ;<br />
&nbsp;&nbsp;&nbsp; info(new xAxaptaUsermanager().getUserSid('h.schweda', 'schweda.net'));<br />
}
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Tue, 27 Sep 2011 21:33:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=416</link>
<comments>http://www.schweda.net/blog_ax.php?bid=416</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=416</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=416</wfw:commentRss>
</item>
<item>
<title>Bearbeiten von Formularfeldern beschränken II</title>
<description><![CDATA[
<p>Sollen in einem Formular nur bestimmte Felder zur Bearbeitung freigegeben sein, kann man die Eigenschaft <em>allowEdit </em>s&auml;mtlicher Felder der DataSource der Tabelle entsprechend umsetzen.
</p>

<p>Einfacher geht&rsquo;s mit folgendem Codebeispiel, welches in der <em>init</em>-Methode der DataSource eingebunden wurde und - im konkreten Fall in der Tabelle <em>SalesLine </em>- nur bei einem einzigen Feld die Bearbeitung erlaubt.
</p>

<p>Im Gegensatz zu einem <a title="Bearbeiten von Formularfeldern beschr&auml;nken" target="_self" href="http://www.schweda.net/blog_ax.php?nid=allowedit1">fr&uuml;her ver&ouml;ffentlichten Beitrag</a> mit dem gleichen Thema werden bei diesem Codebeispiel auch Array-Felder korrekt ber&uuml;cksichtigt.
</p>

<div style="padding: 5px; width: 460px; height: 290px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">public void init()<br />
{<br />
&nbsp;&nbsp;&nbsp; FormDataObject&nbsp; fdo;<br />
&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f;<br />
&nbsp;&nbsp;&nbsp; SysDictTable&nbsp;&nbsp;&nbsp; sysDictTable;<br />
&nbsp;&nbsp;&nbsp; MapEnumerator&nbsp;&nbsp; fdoMapEnumerator;<br />
&nbsp;&nbsp;&nbsp; ; <br />
&nbsp;&nbsp;&nbsp; sysDictTable = new SysDictTable(tablenum(SalesLine));<br />
&nbsp;&nbsp;&nbsp; for(f=1;f&lt;=sysDictTable.fieldCnt();f++)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fdoMapEnumerator = new MapEnumerator(formDataSourceArrayFieldExtObjects(salesLine_ds, sysDictTable.fieldCnt2Id(f)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (fdoMapEnumerator.moveNext())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fdo = fdoMapEnumerator.currentValue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(fdo)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fdo.allowEdit(false);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; fdo = salesLine_ds.object(fieldnum(SalesLine, QtyOrdered));<br />
&nbsp;&nbsp;&nbsp; fdo.allowEdit(true);<br />
}
</div>

<p>Getestet in Dynamics AX 2009
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Sun, 21 Aug 2011 19:34:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=415</link>
<comments>http://www.schweda.net/blog_ax.php?bid=415</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=415</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=415</wfw:commentRss>
</item>
<item>
<title>Datensatzvorlagen ermitteln</title>
<description><![CDATA[
<p>Wer einmal in die Verlegenheit kommt, ermitteln zu m&uuml;ssen ob f&uuml;r eine bestimmte Tabelle Datensatzvorlagen vorhanden sind, f&uuml;r den kann folgendes Code-Beispiel hilfreich sein.
</p>

<p>Im Beispiel wird ermittelt, wieviele Benutzer- bzw. Unternehmensvorlagen es f&uuml;r die Tabelle <em>InventTable </em>gibt und ob der aktuelle Benutzer sich den Vorlagendialog anzeigen l&auml;sst, wenn er/sie einen neuen Artikel anlegt.
</p>

<div style="padding: 5px; width: 460px; height: 260px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void SysRecordTemplatesActive(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; tableId tableId = tableNum(inventTable);<br />
&nbsp;&nbsp;&nbsp; common common = new sysdictTable(tableId).makeRecord();<br />
&nbsp;&nbsp;&nbsp; SysRecordTemplateStorageUser storageUser&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = SysRecordTemplateStorage::newCommon(common, SysRecordTemplateType::User);<br />
&nbsp;&nbsp;&nbsp; SysRecordTemplateStorageCompany storageCompany = SysRecordTemplateStorage::newCommon(common, SysRecordTemplateType::Company);<br />
&nbsp;&nbsp;&nbsp; sysRecordTemplateSelect sysRecordTemplateSelect;<br />
&nbsp;&nbsp;&nbsp; container userTemplates;<br />
&nbsp;&nbsp;&nbsp; container companyTemplates;<br />
&nbsp;&nbsp;&nbsp; ;<br />
&nbsp;&nbsp;&nbsp; // Liste der Vorlagen<br />
&nbsp;&nbsp;&nbsp; userTemplates = storageUser.get();<br />
&nbsp;&nbsp;&nbsp; info(strFmt(&quot;Anzahl Benutzervorlagen f&uuml;r Tabelle %1: %2&quot;, new sysdictTable(tableId).label(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conLen(userTemplates)));<br />
<br />
&nbsp;&nbsp;&nbsp; companyTemplates = storageCompany.get();<br />
&nbsp;&nbsp;&nbsp; info(strFmt(&quot;Anzahl Unternehmensvorlagen f&uuml;r Tabelle %1: %2&quot;, new sysdictTable(tableId).label(), <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conLen(companyTemplates)));<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; // Soll der aktive Benutzer nach Vorlagen gefragt werden?<br />
&nbsp;&nbsp;&nbsp; sysRecordTemplateSelect = SysRecordTemplateSelect::newTableId(tableId);<br />
&nbsp;&nbsp;&nbsp; sysRecordTemplateSelect.load();<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; info(strFmt(&quot;Datensatzvorlagen f&uuml;r die Tabelle %1 in Verwendung: %2&quot;, new sysdictTable(tableId).label(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enum2str(sysRecordTemplateSelect.parmPrompt()))); <br />
}
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Fri, 12 Aug 2011 20:08:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=414</link>
<comments>http://www.schweda.net/blog_ax.php?bid=414</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=414</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=414</wfw:commentRss>
</item>
<item>
<title>Berichte lassen sich nicht über die Stapelverarbeitung ausführen</title>
<description><![CDATA[
<p>Wenn bei einem Benutzer der Register Stapel beim Aufruf eines Berichtes nicht angezeigt wird, kann dies u.U. daran liegen, da&szlig; der Benutzer keine oder unzureichende&nbsp;Berechtigung f&uuml;r den Sicherheitsschl&uuml;ssel <em>Stapelverarbeitungsbericht</em> (SecurityKey <em>BatchReport</em>) hat.
</p>

<p><img width="465" height="206" border="0" alt="" title="Screenshot" src="http://www.schweda.net/pictures/blogpics/axReportBatchTab.jpg" />
</p>

<p><br />
&nbsp;
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Wed, 06 Jul 2011 19:24:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=411</link>
<comments>http://www.schweda.net/blog_ax.php?bid=411</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=411</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=411</wfw:commentRss>
</item>
<item>
<title>Projekte nach einem bestimmten Objekt durchsuchen</title>
<description><![CDATA[
<p>Nachstehender Job durchsucht alle Projekte nach einem bestimmten Element des AOT.
</p>

<p>Daf&uuml;r wird ein Dialog verwendet, wo man lediglich den Namen und den Typ des zu suchenden Elementes angeben muss. Au&szlig;erdem kann man noch einstellen, ob auch die privaten Projektknoten durchsucht werden sollen.
</p>

<div style="padding: 5px; width: 460px; height: 260px; color: rgb(0, 0, 0); overflow: scroll; font-family: courier new,helvetica; font-size: 12px; white-space: nowrap; background-color: rgb(255, 255, 204);">static void findObjectWithinProjects(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; UtilElementType utilElementType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = UtilElementType::Table;<br />
&nbsp;&nbsp;&nbsp; Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; objectName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 'custTable';<br />
&nbsp;&nbsp;&nbsp; boolean&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; includePrivateProjects = false;<br />
&nbsp;&nbsp;&nbsp; Dialog&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dialog;<br />
&nbsp;&nbsp;&nbsp; DialogField&nbsp;&nbsp;&nbsp;&nbsp; df_objectName;<br />
&nbsp;&nbsp;&nbsp; DialogField&nbsp;&nbsp;&nbsp;&nbsp; df_utilElementType;<br />
&nbsp;&nbsp;&nbsp; DialogField&nbsp;&nbsp;&nbsp;&nbsp; df_privateProjects;<br />
&nbsp;&nbsp;&nbsp; container&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conProjects;<br />
&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c;<br />
&nbsp;&nbsp;&nbsp; TreeNode&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; treeNodeRoot;<br />
&nbsp;&nbsp;&nbsp; SysOperationProgress&nbsp;&nbsp;&nbsp; sysOperationProgress;<br />
&nbsp;&nbsp;&nbsp; UtilElementType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; utilElementTypeSelection;&nbsp;&nbsp;&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp; #Aot<br />
&nbsp;&nbsp;&nbsp; #TreeNodeSysNodeType<br />
&nbsp;&nbsp;&nbsp; #AviFiles<br />
&nbsp;&nbsp;&nbsp; #define.objectNameField(&quot;Name of object&quot;)<br />
&nbsp;&nbsp;&nbsp; #define.utilElementTypeField(&quot;Type of object&quot;)<br />
<br />
&nbsp;&nbsp;&nbsp; void findChildNodes(TreeNode _treeNodeParent, ProjectNode _projectNode, str _objectName)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TreeNode&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; treeNode;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TreeNodeIterator&nbsp;&nbsp;&nbsp; treeNodeIterator;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; treeNodeIterator = _treeNodeParent.AOTiterator();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; treeNode = treeNodeIterator.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (treeNode)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (treeNode.AOTgetNodeType() == #NT_PROJECT_GROUP)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; findChildNodes(treeNode, _projectNode, _objectName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (treeNode.AOTname() like _objectName)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; utilElementTypeSelection = str2enum(utilElementTypeSelection, enum2str(utilElementType)); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!utilElementType || treeNode.applObjectType() == utilElementTypeSelection)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!confind(conProjects, _projectNode.AOTname()))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conProjects = conins(conProjects, conlen(conProjects)+1, _projectNode.AOTname());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; treeNode.treeNodeRelease();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; treeNode = treeNodeIterator.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; void loopProjectsNode(TreeNode _treeNode)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ProjectNode projectNode;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TreeNode treeNodeProject; <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (_treeNode)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; treeNodeProject = _treeNode.AOTfirstChild();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (treeNodeProject)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; projectNode = treeNodeProject; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sysOperationProgress.setText(projectNode.name()); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; findChildNodes(projectNode.loadForInspection(), treeNodeProject, objectName); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; treeNodeProject = treeNodeProject.AOTnextSibling();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ; <br />
&nbsp;&nbsp;&nbsp; dialog = new Dialog();<br />
&nbsp;&nbsp;&nbsp; dialog.caption(&quot;Find projects containing specific object&quot;);<br />
&nbsp;&nbsp;&nbsp; df_objectName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = dialog.addField(Types::String, #objectNameField);<br />
&nbsp;&nbsp;&nbsp; df_utilElementType = dialog.addField(typeid(UtilElementType), #utilElementTypeField);<br />
&nbsp;&nbsp;&nbsp; df_privateProjects = dialog.addField(typeid(NoYesId), &quot;Include Private projects&quot;); <br />
&nbsp;&nbsp;&nbsp; df_objectName.value(objectName);<br />
&nbsp;&nbsp;&nbsp; df_utilElementType.value(utilElementType);<br />
&nbsp;&nbsp;&nbsp; df_privateProjects.value(includePrivateProjects); <br />
&nbsp;&nbsp;&nbsp; if( !dialog.run())<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; objectName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = df_objectName.value();<br />
&nbsp;&nbsp;&nbsp; utilElementType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = df_utilElementType.value();<br />
&nbsp;&nbsp;&nbsp; includePrivateProjects = df_privateProjects.value(); <br />
&nbsp;&nbsp;&nbsp; if (objectName == '*' || objectName == '')<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw error(strfmt(&quot;@SYS26332&quot;, #objectNameField));<br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; setprefix(strfmt(&quot;Projects containing %1 '%2'&quot;, utilElementType, objectName)); <br />
<br />
&nbsp;&nbsp;&nbsp; startLengthyOperation(); <br />
<br />
&nbsp;&nbsp;&nbsp; sysOperationProgress = new SysOperationProgress();<br />
&nbsp;&nbsp;&nbsp; sysOperationProgress.setCaption(&quot;Searching&quot;);<br />
&nbsp;&nbsp;&nbsp; sysOperationProgress.setAnimation(#AviSearch); <br />
<br />
&nbsp;&nbsp;&nbsp; // Private projects<br />
&nbsp;&nbsp;&nbsp; if(includePrivateProjects)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loopProjectsNode(SysTreeNode::getPrivateProject());<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; // Shared projects<br />
&nbsp;&nbsp;&nbsp; loopProjectsNode(SysTreeNode::getSharedProject()); <br />
&nbsp;&nbsp;&nbsp; sysOperationProgress.kill();<br />
&nbsp;&nbsp;&nbsp; endLengthyOperation(); <br />
<br />
&nbsp;&nbsp;&nbsp; // List projects<br />
&nbsp;&nbsp;&nbsp; for(c=1;c&lt;=conlen(conProjects);c++)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(conpeek(conProjects, c));<br />
&nbsp;&nbsp;&nbsp; }<br />
}
</div>

<p>Wer eine etwas komfortablere M&ouml;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.
</p>

<p><a href="https://www.loncartechnologies.com/download.php">https://www.loncartechnologies.com/download.php</a>
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Wed, 29 Jun 2011 19:36:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=343</link>
<comments>http://www.schweda.net/blog_ax.php?bid=343</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=343</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=343</wfw:commentRss>
</item>
<item>
<title>Berechtigung eines Benutzers für einen Sicherheitsschlüssel abfragen</title>
<description><![CDATA[
<p>Mit diesem St&uuml;ckchen Code kann man in Dynamics AX pr&uuml;fen, welche Berechtigung ein Benutzer f&uuml;r einen bestimmten Sicherheitsschl&uuml;ssel (Securitykey) hat.
</p>

<div style="padding: 5px; background-color: rgb(255, 255, 204); width: 460px; font-family: courier new,helvetica; white-space: nowrap; height: 260px; color: rgb(0, 0, 0); font-size: 12px; overflow: scroll;">static void GetSecurityKeyAccess4User(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; Dictionary&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dictionary = new Dictionary();<br />
&nbsp;&nbsp;&nbsp; securityKeyId&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; securityKeyId;<br />
&nbsp;&nbsp;&nbsp; SecurityKeySet&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; securityKeySet = new SecurityKeySet();<br />
&nbsp;&nbsp;&nbsp; UserId&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userId = 'user1';<br />
&nbsp;&nbsp;&nbsp; SelectableDataArea&nbsp; dataArea = 'ceu';<br />
&nbsp;&nbsp;&nbsp; AccessType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; accessType;<br />
&nbsp;&nbsp;&nbsp; ;<br />
<br />
&nbsp;&nbsp;&nbsp; securityKeyId = Dictionary.securityKeyName2Id(&quot;BatchReport&quot;);<br />
<br />
&nbsp;&nbsp;&nbsp; securityKeySet.loadUserRights(userId, dataArea);<br />
<br />
&nbsp;&nbsp;&nbsp; AccessType = securityKeySet.access(securityKeyId);<br />
<br />
&nbsp;&nbsp;&nbsp; info(enum2str(AccessType));<br />
}
</div>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Fri, 24 Jun 2011 20:49:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=410</link>
<comments>http://www.schweda.net/blog_ax.php?bid=410</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=410</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=410</wfw:commentRss>
</item>
<item>
<title>AX 2012: Having-Clause über addHavingFilter</title>
<description><![CDATA[
<p>Ein neues Feature von Dynamics AX 2012 ist, da&szlig; man nun bei einem Query auch eine HAVING-Clause hinzuf&uuml;gen kann.
</p>

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

<p>Microsoft hat dies scheinbar eingesehen, und stellt nun bei der Verwendung von Queries die Methode <strong>addHavingFilter </strong>zur Verf&uuml;gung.
</p>

<p>Im folgenden Beispiel m&ouml;chte ich mir z.B. alle Kundengruppen ausgeben lassen, die bei mehr als nur einem Kunden hinterlegt sind.
</p>

<div style="padding-bottom: 5px; background-color: rgb(255,255,204); padding-left: 5px; width: 460px; padding-right: 5px; font-family: courier new,helvetica; white-space: nowrap; height: 260px; color: rgb(0,0,0); font-size: 12px; overflow: scroll; padding-top: 5px">static void AX2012_QueryHavingFilter(Args _args)<br />
{<br />
&nbsp;&nbsp;&nbsp; query query;<br />
&nbsp;&nbsp;&nbsp; QueryRun QueryRun;<br />
&nbsp;&nbsp;&nbsp; QueryBuildDataSource QueryBuildDataSource;<br />
&nbsp;&nbsp;&nbsp; CustTable custTable;<br />
&nbsp;&nbsp;&nbsp; ;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; setPrefix(funcName());<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; // Build query<br />
&nbsp;&nbsp;&nbsp; query = new query();<br />
&nbsp;&nbsp;&nbsp; QueryBuildDataSource = query.addDataSource(tableNum(CustTable));<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; // Add fields to query<br />
&nbsp;&nbsp;&nbsp; QueryBuildDataSource.addGroupByField(fieldNum(CustTable, CustGroup));<br />
&nbsp;&nbsp;&nbsp; QueryBuildDataSource.addSelectionField(fieldNum(custTable, recId), SelectionField::Count);

<p>&nbsp;
</p>

<p>&nbsp;&nbsp;&nbsp; // Add having filter to query&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; query.addHavingFilter(QueryBuildDataSource, &quot;recId&quot;, AggregateFunction::Count).value(&quot;&gt;1&quot;);<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; // Run query<br />
&nbsp;&nbsp;&nbsp; QueryRun = new QueryRun(query);<br />
&nbsp;&nbsp;&nbsp; while(QueryRun.next())<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; custTable = QueryRun.get(tableNum(custTable));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info(strFmt(&quot;Custgroup %1: %2 records&quot;, custTable.CustGroup, custTable.RecId));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; }<br />
}
</p>

</div>

<p>Das Ergebnis der oben stehenden Abfrage ohne <strong>addHavingFilter </strong>w&uuml;rde wie folgt aussehen:
</p>

<p><img width="232" height="170" border="0" src="http://www.schweda.net/pictures/blogpics/ax2012_addhavingfilter_1.jpg" alt="" />
</p>

<p>Mit <strong>addHavingFilter </strong>&auml;ndert sich das Ergebnis/Infolog:
</p>

<p><img width="228" height="131" border="0" src="http://www.schweda.net/pictures/blogpics/ax2012_addhavingfilter_2.jpg" alt="" />
</p>

<p>Nat&uuml;rlich kann man dieses neue Feature auch bei einem im AOT definierten Query einsetzen.&nbsp;Dazu gibt es einen neuen, entsprechend benannten&nbsp;Knoten:
</p>

<p><img width="296" height="241" border="0" src="http://www.schweda.net/pictures/blogpics/ax2012_addhavingfilter_aot.jpg" alt="" />&nbsp;
</p>]]></description>
<category>Microsoft Dynamics AX (Axapta)</category>
<pubDate>Fri, 03 Jun 2011 21:41:00 +0200</pubDate>
<link>http://www.schweda.net/blog_ax.php?bid=405</link>
<comments>http://www.schweda.net/blog_ax.php?bid=405</comments>
<guid isPermaLink="true">http://www.schweda.net/blog_ax.php?bid=405</guid>
<author>heinz.schweda@schweda.net (Heinz Schweda)</author><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Heinz Schweda</dc:creator><wfw:commentRss>http://www.schweda.net/blog_ax.php?bid=405</wfw:commentRss>
</item>
</channel>
</rss>	



