<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4865774416414395121</id><updated>2012-02-16T17:46:24.184-05:00</updated><category term='Multi-AOS'/><category term='Tools'/><category term='Fixed Assets'/><category term='Documentation'/><category term='Tips'/><category term='AX 4.0'/><category term='Fun'/><category term='Certification'/><category term='Concept'/><category term='AX 2009'/><category term='Finance'/><category term='SSRS'/><title type='text'>Nate's Dynamics AX Notebook</title><subtitle type='html'>Dynamics AX (Axapta) Implementation, Architecture, and Development</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>28</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-9118792159214645040</id><published>2012-01-18T14:10:00.004-05:00</published><updated>2012-01-18T14:26:59.581-05:00</updated><title type='text'>Run-time add/remove datasource to filter results</title><content type='html'>Sometimes I add a Combobox above a Grid to give the user several 'canned' filters.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-Uya5Pd5RnQ4/TxcUglZGgTI/AAAAAAAAAFo/kzO2dfPNCAE/s1600/ScreenShot953.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-Uya5Pd5RnQ4/TxcUglZGgTI/AAAAAAAAAFo/kzO2dfPNCAE/s1600/ScreenShot953.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;In some cases I would like to filter on a table other than the one displayed in the grid.&amp;nbsp; For example, I might want to filter a grid of CustTable records based on related Address table records.&lt;br /&gt;&lt;br /&gt;If you want the filter to be active all the time, you can just add the filtering datasource to your form.&amp;nbsp; But if you only want the filter to be active some of the time, you need to be able to dynamically (run-time) add and remove the datasource that does the filtering.&lt;br /&gt;&lt;br /&gt;The code below shows how to dynamically add and remove (actually disable) a child datasource for filtering purposes. &lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;public void executeQuery() //on form datasource "formDatasourceName"&lt;br /&gt;{&lt;br /&gt;    QueryBuildDataSource    qbds;&lt;br /&gt;    ;&lt;br /&gt; &lt;br /&gt;    if(this.query().dataSourceName("formDatasourceName").childDataSourceCount() == 1)&lt;br /&gt;    {&lt;br /&gt;        //if the filter datasource has been added in the past (prior run of executeQuery), disable it&lt;br /&gt;        this.query().dataSourceName("formDatasourceName").childDataSourceNo(1).enabled(false);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (booleanFilterResults)&lt;br /&gt;    {&lt;br /&gt;        //this creates a "hidden" exists join to act as a filter&lt;br /&gt;        if (this.query().dataSourceName("formDatasourceName").childDataSourceCount() == 1)&lt;br /&gt;        {&lt;br /&gt;            //if the filter datasource&lt;br /&gt;            qbds = this.query().dataSourceName("formDatasourceName").childDataSourceNo(1);&lt;br /&gt;            qbds.enabled(true);&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            qbds = this.query().dataSourceName("formDatasourceName").addDataSource(tablenum(filterTableName));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        qbds.clearRanges();&lt;br /&gt;&lt;br /&gt;        qbds.relations(true);  //or use .addLink...&lt;br /&gt;        qbds.joinMode(JoinMode::ExistsJoin);&lt;br /&gt;        qbds.fetchMode(queryfetchmode::One2One);&lt;br /&gt;        &lt;br /&gt;        //filter on some value, in this case a comboBox selection.  &lt;br /&gt;        //Of course you'll call formDatasourceName.executeQuery() in comboBoxFilter modified method&lt;br /&gt;        qbds.addRange(fieldnum(filterTableName, ItemId)).value(queryValue(comboBoxFilter.valueStr()));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    super();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-9118792159214645040?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/9118792159214645040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2012/01/dynamically-add-datasource-to-form-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/9118792159214645040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/9118792159214645040'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2012/01/dynamically-add-datasource-to-form-to.html' title='Run-time add/remove datasource to filter results'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-Uya5Pd5RnQ4/TxcUglZGgTI/AAAAAAAAAFo/kzO2dfPNCAE/s72-c/ScreenShot953.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-6600500992037928223</id><published>2011-06-08T18:47:00.004-04:00</published><updated>2011-06-24T06:48:29.742-04:00</updated><title type='text'>Inventory Journal Import</title><content type='html'>I wrote a simple class to handle csv imports into Movement Journals.&lt;br /&gt;&lt;br /&gt;1. Create a Movement Journal and go into the Lines screen.&lt;br /&gt;2. Select Functions, Import Lines&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-MuBYy6sX0vM/Te-4PJEahvI/AAAAAAAAAEU/YaGI_Db-l2g/s1600/iji1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="112" src="http://4.bp.blogspot.com/-MuBYy6sX0vM/Te-4PJEahvI/AAAAAAAAAEU/YaGI_Db-l2g/s400/iji1.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;3. Select a csv file with the columns: ItemId, Warehouse, Location, Batch, Qty, Cost.&amp;nbsp; (you can mod the code to expand this)&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-HzRs6664IhY/Te-4Re2CAWI/AAAAAAAAAEY/iQNZwhg0TSQ/s1600/iji2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="190" src="http://4.bp.blogspot.com/-HzRs6664IhY/Te-4Re2CAWI/AAAAAAAAAEY/iQNZwhg0TSQ/s400/iji2.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;4. The lines are added to the journal.&lt;br /&gt;&lt;br /&gt;You can download the xpo below, and here are some of the key bits of code.&lt;br /&gt;&lt;br /&gt;Create a class (mine is called inventJournalImport) extending runbase.&amp;nbsp; Create a menu item (action) for the class and drop it on the InventJournalMovement form.&lt;br /&gt;&lt;br /&gt;The main method of the class is as follows:&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;client static void main(Args args)&lt;br /&gt;{&lt;br /&gt;    inventJournalImport             inventJournalImport;&lt;br /&gt;    Object                          formRunObject;&lt;br /&gt;    JournalForm                     journalForm;&lt;br /&gt;    InventJournalId                 inventJournalId;&lt;br /&gt;    FormDataSource                  journalTrans_ds;&lt;br /&gt;    ;&lt;br /&gt;&lt;br /&gt;    inventJournalImport = new inventJournalImport();&lt;br /&gt;    inventJournalImport.getLast();&lt;br /&gt;&lt;br /&gt;    if (!args || !args.caller() || args.caller().name() != formStr(InventJournalMovement))&lt;br /&gt;    {&lt;br /&gt;        throw error(strfmt("This function must be called from the %1 form.", formStr(InventJournalMovement)));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (formHasMethod(args.caller(), identifierstr(journalForm)))&lt;br /&gt;    {&lt;br /&gt;        formRunObject = args.caller();&lt;br /&gt;&lt;br /&gt;        journalForm = formRunObject.journalForm();&lt;br /&gt;        inventJournalImport.parmJournalForm(journalForm);  //needed to index numOfLines on inventJournalTable&lt;br /&gt;&lt;br /&gt;        inventJournalId = journalForm.journalTableData().journalTable().JournalId;&lt;br /&gt;        inventJournalImport.parmInventJournalId(inventJournalId);  //for defaulting on the imported lines&lt;br /&gt;&lt;br /&gt;        journalTrans_ds = journalForm.journalTransData().journalTrans().dataSource();  //for .executeQuery, below&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (inventJournalImport.prompt())&lt;br /&gt;    {&lt;br /&gt;        inventJournalImport.ImportRecords();&lt;br /&gt;&lt;br /&gt;        //refresh the grid&lt;br /&gt;        journalTrans_ds.executeQuery();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The ImportRecords method is below.&amp;nbsp; There is a dialog in the class that fills filename and transactionDate.&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;void ImportRecords()&lt;br /&gt;{&lt;br /&gt;    AsciiIo             asciiIo;&lt;br /&gt;    container           con;&lt;br /&gt;    FileIoPermission    fioPermission;&lt;br /&gt;&lt;br /&gt;    InventJournalTrans  inventJournalTrans;&lt;br /&gt;    InventDim           inventDim;&lt;br /&gt;&lt;br /&gt;    wmsLocationId       wmsLocationId;&lt;br /&gt;    inventLocationId    inventLocationId;&lt;br /&gt;    inventBatchId       inventBatchId;&lt;br /&gt;&lt;br /&gt;    boolean             useDefaultInventDim, useDefaultCost;&lt;br /&gt;    int                 imported;&lt;br /&gt;    ;&lt;br /&gt;&lt;br /&gt;    if (WINAPI::fileExists(fileName))&lt;br /&gt;    {&lt;br /&gt;        //show wait cursor&lt;br /&gt;        startLengthyOperation();&lt;br /&gt;&lt;br /&gt;        // The AsciiIO.new method runs under code access permission.&lt;br /&gt;        fioPermission = new FileIoPermission(fileName,"R");&lt;br /&gt;&lt;br /&gt;        if (fioPermission == null)&lt;br /&gt;        {&lt;br /&gt;            info(strfmt("Not able to read file: %1",fileName));&lt;br /&gt;            return;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // Code access permission scope starts here.&lt;br /&gt;        fioPermission.assert();&lt;br /&gt;&lt;br /&gt;        ttsbegin;&lt;br /&gt;&lt;br /&gt;        asciiIo = new AsciiIo(fileName,"R");&lt;br /&gt;        asciiIo.inFieldDelimiter(",");&lt;br /&gt;        if (asciiIo != null)&lt;br /&gt;        {&lt;br /&gt;            con = asciiIo.read();&lt;br /&gt;&lt;br /&gt;            while (asciiIo.status() == IO_Status::Ok)&lt;br /&gt;            {&lt;br /&gt;                try&lt;br /&gt;                {&lt;br /&gt;                    //1-itemId, 2-warehouse, 3-location, 4-batch, 5-qty, 6-cost&lt;br /&gt;                    inventJournalTrans.clear();&lt;br /&gt;                    inventJournalTrans.TransDate = transactionDate;&lt;br /&gt;                    inventJournalTrans.JournalId = journalId;&lt;br /&gt;                    inventJournalTrans.initFromInventJournalTable(inventJournalTrans.inventJournalTable());&lt;br /&gt;&lt;br /&gt;                    inventJournalTrans.ItemId = strLTrim(strRTrim(conpeek(con,1)));&lt;br /&gt;&lt;br /&gt;                    inventLocationId = strLTrim(strRTrim(conpeek(con,2)));&lt;br /&gt;                    wmsLocationId = strLTrim(strRTrim(conpeek(con,3)));&lt;br /&gt;                    inventBatchId = strLTrim(strRTrim(conpeek(con,4)));&lt;br /&gt;                    if (inventLocationId || wmsLocationId || inventBatchId)&lt;br /&gt;                    {&lt;br /&gt;                        useDefaultInventDim = false;&lt;br /&gt;&lt;br /&gt;                        inventDim.clear();&lt;br /&gt;                        inventDim.InventLocationId = inventLocationId;&lt;br /&gt;                        inventDim.wMSLocationId = wmsLocationId;&lt;br /&gt;                        inventDim.inventBatchId = inventBatchId;&lt;br /&gt;                        inventDim = InventDim::findOrCreate(inventDim);&lt;br /&gt;&lt;br /&gt;                        inventJournalTrans.InventDimId = inventDim.inventDimId;&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        useDefaultInventDim = true;&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    inventJournalTrans.Qty = str2num(strLTrim(strRTrim(conpeek(con,5))));&lt;br /&gt;                    inventJournalTrans.Qty= decround(inventJournalTrans.Qty,InventTable::inventDecimals(inventJournalTrans.ItemId));&lt;br /&gt;&lt;br /&gt;                    if (inventJournalTrans.Qty &amp;gt; 0)&lt;br /&gt;                    {&lt;br /&gt;                        //import the cost if this is an addition to inventory&lt;br /&gt;                        useDefaultCost = false;&lt;br /&gt;                        inventJournalTrans.CostPrice          = str2num(strLTrim(strRTrim(conpeek(con,6))));&lt;br /&gt;                        inventJournalTrans.PriceUnit          = 1;&lt;br /&gt;                        inventJournalTrans.CostMarkup         = 0;&lt;br /&gt;                        inventJournalTrans.CostAmount         = inventJournalTrans.calcCostAmount();&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        useDefaultCost = true;&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    inventJournalTrans.initFromInventTable(inventJournalTrans.inventTable(),false, useDefaultInventDim, useDefaultCost);&lt;br /&gt;&lt;br /&gt;                    inventJournalTrans.insertFromCode();&lt;br /&gt;                    imported++;&lt;br /&gt;&lt;br /&gt;                    //updates the number of lines count on the journal table&lt;br /&gt;                    journalForm.journalTableData().addTotal(inventJournalTrans);&lt;br /&gt;                }&lt;br /&gt;                catch (Exception::Error)&lt;br /&gt;                {&lt;br /&gt;                    exceptionTextFallThrough();&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                con = asciiIo.read();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // revertAssert is not really necessary here because the method is ending.&lt;br /&gt;        CodeAccessPermission::revertAssert();&lt;br /&gt;&lt;br /&gt;        ttscommit;&lt;br /&gt;        info (strfmt("%1 records imported", imported));&lt;br /&gt;&lt;br /&gt;        //remove wait cursor&lt;br /&gt;        endLengthyOperation();&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        error(strfmt("Import File not found: %1",fileName));&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;That's the bulk of the code.&amp;nbsp; You can download the xpo below to see everything.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://goo.gl/C0dDJ"&gt;SharedProject_InventoryJournalImport.xpo (google docs - shortened via goo.gl - 12kb)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-6600500992037928223?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/6600500992037928223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2011/06/inventory-journal-import.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/6600500992037928223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/6600500992037928223'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2011/06/inventory-journal-import.html' title='Inventory Journal Import'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-MuBYy6sX0vM/Te-4PJEahvI/AAAAAAAAAEU/YaGI_Db-l2g/s72-c/iji1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-8806458444290489695</id><published>2011-06-02T15:28:00.001-04:00</published><updated>2011-06-02T15:29:40.037-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><category scheme='http://www.blogger.com/atom/ns#' term='AX 2009'/><title type='text'>Inventory Turns Report</title><content type='html'>AX doesn't really have a good inventory turns report.&amp;nbsp; Here's a simple job that calculates inventory turns by quantity and by value.&amp;nbsp; You can adapt the code to run in a report.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;static void InventoryTurns(Args _args)&lt;br /&gt;{&lt;br /&gt;    itemId          itemId;&lt;br /&gt;    inventTrans     inventTrans;&lt;br /&gt;    inventSum       inventSum;&lt;br /&gt;    qty             thisQty, qtyOnHand, totalDailyQtyOnHand, avgDailyQtyOnHand, usageQty;&lt;br /&gt;    Amount          thisValue, valueOnHand, totalDailyValueOnHand, avgDailyValueOnHand, usageValue;&lt;br /&gt;    Real            turnsByQty, turnsByValue;&lt;br /&gt;    date            lastDate, fromDate, toDate;&lt;br /&gt;    ;&lt;br /&gt;&lt;br /&gt;    //set the itemID and date range&lt;br /&gt;    itemId = '00001';&lt;br /&gt;    fromDate = mkDate(1,1,2010);&lt;br /&gt;    toDate = mkDate(31,12,2010);&lt;br /&gt;&lt;br /&gt;    //****average daily on-hand&lt;br /&gt;    lastDate = systemDateGet(); //initialize with today.&lt;br /&gt;&lt;br /&gt;    //inventSum contains today's values for qty and value&lt;br /&gt;    while select inventSum where inventSum.ItemId == itemId &amp;amp;&amp;amp; inventSum.Closed == NoYes::No&lt;br /&gt;    {&lt;br /&gt;        qtyOnHand += inventSum.PhysicalInvent;&lt;br /&gt;        valueOnHand += (inventSum.PhysicalValue + inventSum.PostedValue);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    //starting with today, we work backward to the from date and manually calculate what the on-hand qty/value was each day&lt;br /&gt;    while (lastDate &amp;gt;= fromDate)&lt;br /&gt;    {&lt;br /&gt;        if (lastDate &amp;lt;= toDate) //if we're within the date range, then sum the on-hand qty/value for determination of the average&lt;br /&gt;        {&lt;br /&gt;            //add one days worth of the current OnHand figures&lt;br /&gt;            totalDailyQtyOnHand += qtyOnHand;&lt;br /&gt;            totalDailyValueOnHand += valueOnHand;&lt;br /&gt;&lt;br /&gt;            //update average calc&lt;br /&gt;            avgDailyQtyOnHand = totalDailyQtyOnHand/((toDate + 1) - lastDate);&lt;br /&gt;            avgDailyValueOnHand = totalDailyValueOnHand/((toDate + 1) - lastDate);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        lastDate --;&lt;br /&gt;&lt;br /&gt;        thisQty = 0;&lt;br /&gt;        thisValue = 0;&lt;br /&gt;        while select Qty, CostAmountPosted, CostAmountPhysical from inventTrans&lt;br /&gt;            where inventTrans.ItemId == itemId&lt;br /&gt;            &amp;amp;&amp;amp; inventTrans.DatePhysical == lastDate&lt;br /&gt;        {&lt;br /&gt;            thisQty += inventTrans.Qty;&lt;br /&gt;            //use the posted (financial) value if available&lt;br /&gt;            if (inventTrans.CostAmountPosted != 0)&lt;br /&gt;            {&lt;br /&gt;                thisValue += inventTrans.CostAmountPosted;&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;                thisValue += inventTrans.CostAmountPhysical;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        //calc the new onHand values&lt;br /&gt;        qtyOnHand += -1 * thisQty;&lt;br /&gt;        valueOnHand += -1 * thisValue;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    //****annual usage&lt;br /&gt;    while select inventTrans&lt;br /&gt;        order by DatePhysical desc&lt;br /&gt;        where inventTrans.ItemId == itemId&lt;br /&gt;        &amp;amp;&amp;amp; inventTrans.datePhysical &amp;gt;= fromDate  //this should work in place of limits on statusIssue &amp;lt; 3 and statusReceipt &amp;lt; 3&lt;br /&gt;        &amp;amp;&amp;amp; inventTrans.datePhysical &amp;lt;= toDate&lt;br /&gt;        &amp;amp;&amp;amp; (inventTrans.TransType == InventTransType::Sales&lt;br /&gt;            || inventTrans.TransType == InventTransType::ProdLine&lt;br /&gt;            || inventTrans.TransType == InventTransType::Project&lt;br /&gt;            || inventTrans.TransType == InventTransType::InventTransaction)&lt;br /&gt;&lt;br /&gt;    {&lt;br /&gt;        usageQty += -1*inventTrans.Qty;&lt;br /&gt;        usageValue += -1*inventTrans.CostAmountPhysical;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    //****calc turns = usageQty divided by average on-hand qty&lt;br /&gt;    if (avgDailyQtyOnHand == 0)  //divide by zero protection&lt;br /&gt;    {&lt;br /&gt;        turnsByQty = 0;&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        turnsByQty = usageQty / avgDailyQtyOnHand;&lt;br /&gt;    }&lt;br /&gt;    if (avgDailyValueOnHand == 0)&lt;br /&gt;    {&lt;br /&gt;        turnsByValue = 0;&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        turnsByValue = usageValue / avgDailyValueOnHand;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    info(strfmt("Item Id: %1, Turns by Qty: %2, Turns by Value: %3",itemId,turnsByQty,turnsByValue));&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-8806458444290489695?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/8806458444290489695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2011/06/inventory-turns-report.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/8806458444290489695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/8806458444290489695'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2011/06/inventory-turns-report.html' title='Inventory Turns Report'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-1271982323821826384</id><published>2011-03-29T11:56:00.003-04:00</published><updated>2011-03-29T12:26:55.343-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Concept'/><title type='text'>Accounts Receivable Collections Management</title><content type='html'>Today I'm going to give a tour of a custom &lt;b&gt;Collections Management&lt;/b&gt; screen. Normally, I wouldn't share business process level customizations, but since the Financial modules are fairly independent of business process, I thought this might be of interest.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Need:&lt;/b&gt;&lt;br /&gt;This business unit has several thousand customers and needed a convenient way to manage the processes of collecting on overdue accounts. &lt;br /&gt;&lt;br /&gt;The &lt;b&gt;primary goals&lt;/b&gt; were to:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;easily identify and prioritize customers to contact&lt;/li&gt;&lt;li&gt;enable an informed conversation with the customer by clearly displaying the transactions in question&lt;/li&gt;&lt;li&gt;provide 'relationship management' features - a quick note saying "On May 29th I talked with Seth and he said the check would be cut that day"&lt;/li&gt;&lt;li&gt;make it easy to see how the customer performed in the past when they had an overdue balance&lt;/li&gt;&lt;/ol&gt;These 4 goals match the 4 tabs shown below.&lt;br /&gt;&lt;br /&gt;So, let's begin the tour of the Collections Workbench.&amp;nbsp; I'll mostly let the screenshots do the talking.&lt;br /&gt;&lt;b&gt;Overview Tab &lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-m_bcIUnDaMU/TZHxrMlvzmI/AAAAAAAAADY/5IGnIy7T5Dc/s1600/c1.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="164" src="http://2.bp.blogspot.com/-m_bcIUnDaMU/TZHxrMlvzmI/AAAAAAAAADY/5IGnIy7T5Dc/s640/c1.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span id="goog_1170112203"&gt;&lt;/span&gt;&lt;span id="goog_1170112204"&gt;&lt;/span&gt;&lt;br /&gt;Note: Grid filter is turned on by default for quick searching by customer name, account&lt;br /&gt;&lt;u&gt;Columns&lt;/u&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Tickler Date - user is able to set as a reminder to follow up&lt;/li&gt;&lt;li&gt;Name, Customer account -&amp;nbsp; for quick filtering via grid filter (which is turned on by default)&lt;/li&gt;&lt;li&gt;State - shown so we'd know the time zone for telephone calls &lt;/li&gt;&lt;li&gt;First Review - this is the date that the collections agent first clicks onto the transactions tab for the given record.&amp;nbsp; It's a bit casual, but seems to work well.&lt;/li&gt;&lt;li&gt;Notes - Quick view of most recent note.&amp;nbsp; We'll talk about this more on Tab #3 (Contacts/Notes).&amp;nbsp;&lt;/li&gt;&lt;li&gt;Created Date - when the customer first became overdue&lt;/li&gt;&lt;li&gt;Closed Date - when the customer was no longer overdue.&amp;nbsp; We'll talk about this more on Tab #4 (Closed Notes).&lt;/li&gt;&lt;/ol&gt;&lt;u&gt;Buttons&lt;/u&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Refresh Records - we chose to require a manual refresh of these records rather than calculating them in a batch job or real time.&lt;/li&gt;&lt;li&gt;Customers - link the customer record  (standard AX)&lt;/li&gt;&lt;li&gt;Contact Person - link the the full list of contacts for that customer  (standard AX) - see also Tab #3 (Contacts/Notes)&lt;/li&gt;&lt;li&gt;Open Transaction Editing - link to view/edit open transactions (standard AX)&lt;/li&gt;&lt;li&gt;Aging bucket statistics - link to show AR aging  (standard AX)&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;Tickler Date Buttons&lt;/b&gt;&lt;br /&gt;Tickler setup button show the following setup form that each user can use to configure their screen.&amp;nbsp; The dynamics buttons are created (i.e. "Tickler + 10 Days") and persisted in the usage data.&amp;nbsp; When the user clicks the button, the tickler date is 'pushed out' 10 days.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-_vDCRuj_XAc/TZH231dF_lI/AAAAAAAAADc/dAAQY4pbCW4/s1600/c5.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="215" src="http://2.bp.blogspot.com/-_vDCRuj_XAc/TZH231dF_lI/AAAAAAAAADc/dAAQY4pbCW4/s320/c5.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Transactions Tab&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-jJhQZPibd0M/TZH39IfCfsI/AAAAAAAAADg/OQVauquCzDs/s1600/c2.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="220" src="http://2.bp.blogspot.com/-jJhQZPibd0M/TZH39IfCfsI/AAAAAAAAADg/OQVauquCzDs/s640/c2.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The user can view all open transactions and see which ones are contributing to the past due amount.&lt;br /&gt;The user can print on invoice original or copy as the customer has many times 'lost' the invoice.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Contacts/Notes Tab&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-W4SQIenDlMA/TZH4s-e978I/AAAAAAAAADk/8Qa1gVjWqrk/s1600/c3.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="166" src="http://2.bp.blogspot.com/-W4SQIenDlMA/TZH4s-e978I/AAAAAAAAADk/8Qa1gVjWqrk/s640/c3.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The contacts are shown so that the user can have a list in front of them during a phone call.&lt;br /&gt;&lt;br /&gt;Notes field - this is essentially a 'journal' of the conversations and actions taken regarding this account.&lt;br /&gt;&lt;br /&gt;Each time the user clicks the "Insert Stamp" button, a new line is added to the top of the Notes with their user ID/ date and places the cursor ready for them to type.&amp;nbsp; I've used this "Insert Stamp" concept lots of places and the users really like it.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Closed Notes Tab&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-TzFlb8p1LEE/TZH5zCfex6I/AAAAAAAAADo/tmlvp0c6Ej8/s1600/c4.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-TzFlb8p1LEE/TZH5zCfex6I/AAAAAAAAADo/tmlvp0c6Ej8/s1600/c4.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This tab gives visibility to previous collections records for this customer.&amp;nbsp; In the example above, the customer had an overdue balance from 9/14 to 9/30/2010.&amp;nbsp; On the overview tab, you can see that there is a filter to show only record with no Closed Date.&amp;nbsp; The records on the Closed Notes tab are the opposite.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-1271982323821826384?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/1271982323821826384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2011/03/accounts-receivable-collections.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/1271982323821826384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/1271982323821826384'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2011/03/accounts-receivable-collections.html' title='Accounts Receivable Collections Management'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-m_bcIUnDaMU/TZHxrMlvzmI/AAAAAAAAADY/5IGnIy7T5Dc/s72-c/c1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-7631311402722561624</id><published>2010-12-09T09:48:00.003-05:00</published><updated>2010-12-09T09:56:21.236-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Finance'/><title type='text'>AP or AR Accruals</title><content type='html'>This is a little trick that we've found useful to:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;shorten AP check stubs that were many pages long&lt;/li&gt;&lt;li&gt;allow pre-processing of AR checks that settle against many invoices&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;AR&lt;/b&gt;&lt;br /&gt;We had the situation where we were receiving advance notice of a payment coming from a customer (this could be useful for EDI, etc).&amp;nbsp; For us, the checks settle against lots of invoices - often in the thousands - and we wanted to do the work of settling the payment against the proper invoices ahead of time so that when the check actually arrived, it was quick to process.&lt;br /&gt;&lt;br /&gt;We did this by creating Payment Journal 'accrual' transaction where there is a debit and credit canceled each other out. The offset account is arbitrary because the transaction just goes in and out.&amp;nbsp; In the example below, you can see two anticipated checks represented.&amp;nbsp; Note that the journal balance is 0 - no net effect. &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_5AVFZZy80To/TQDlSyD7MlI/AAAAAAAAACI/C_zF0skobeA/s1600/accrualExample.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="199" src="http://2.bp.blogspot.com/_5AVFZZy80To/TQDlSyD7MlI/AAAAAAAAACI/C_zF0skobeA/s640/accrualExample.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Use the Function, Settlement button to settle one side of the transactions against the open invoices that will be paid.&amp;nbsp; This leaves a single open transaction to settle against when the check actually arrives.&amp;nbsp; (Alternatively, you can use the open transaction editing screen to do the settlement against the invoices)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;AP&lt;/b&gt;&lt;br /&gt;On the AP side, we've used this method to handle the situation where a check is paying for many AP invoices.&amp;nbsp; In this case the problem was that the check stubs were very long and caused many checks to be voided so that all the invoice lines could be printed.&amp;nbsp; We solved this by entering an 'accrual' Invoice Journal transaction and settling it against the many invoices.&amp;nbsp; Then the other side of the transaction is settle against by the Payment Journal and only one line shows on the check stub.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-7631311402722561624?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/7631311402722561624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/12/ap-or-ar-accruals.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/7631311402722561624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/7631311402722561624'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/12/ap-or-ar-accruals.html' title='AP or AR Accruals'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_5AVFZZy80To/TQDlSyD7MlI/AAAAAAAAACI/C_zF0skobeA/s72-c/accrualExample.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-3518883648796763428</id><published>2010-12-02T13:49:00.000-05:00</published><updated>2010-12-02T13:49:01.111-05:00</updated><title type='text'>Cruft</title><content type='html'>I just learned a new word: cruft. (&lt;a href="http://en.wikipedia.org/wiki/Cruft"&gt;http://en.wikipedia.org/wiki/Cruft)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-3518883648796763428?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/3518883648796763428/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/12/cruft.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/3518883648796763428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/3518883648796763428'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/12/cruft.html' title='Cruft'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-6141483088675373669</id><published>2010-10-27T20:34:00.000-04:00</published><updated>2010-10-27T20:34:13.428-04:00</updated><title type='text'>Mark All for Open Cust Trans and Open Vend Trans</title><content type='html'>We have situations where there are lots of open transactions that need to be settled against each other.&amp;nbsp; This can be the case if auto settlement is turned off.&lt;br /&gt;&lt;br /&gt;One solution is to add a "Mark All" button to the custOpenTrans or vendOpenTrans forms.&amp;nbsp; This button "checks" the mark checkbox on every line.&amp;nbsp; The user can then uncheck several lines if needed and Update to settle the lines.&lt;br /&gt;&lt;br /&gt;The code below is an example of what we used on the open vendor transaction screen.&amp;nbsp; The code is very similar on the AR side.&amp;nbsp; One note: I used vendTable.AccountNum in the code below.&amp;nbsp; That should be generalized to work with any buffer that is passed into the open trans form.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;void customMarkAll()&lt;br /&gt;{&lt;br /&gt;    VendTransOpen   localVendTransOpen;&lt;br /&gt;    VendTrans       localVendTrans;&lt;br /&gt;    container       conSum;&lt;br /&gt;&lt;br /&gt;    int             linesProcessed;&lt;br /&gt;    ;&lt;br /&gt;&lt;br /&gt;    //show wait cursor&lt;br /&gt;    startLengthyOperation();&lt;br /&gt;&lt;br /&gt;    element.lock();&lt;br /&gt;&lt;br /&gt;    //remove all prior markings&lt;br /&gt;    specOffsetVoucher.deleteSpecifications();&lt;br /&gt;    settle.empty();&lt;br /&gt;&lt;br /&gt;    ttsbegin;&lt;br /&gt;    while select localVendTransOpen where localVendTransOpen.AccountNum == vendTable.AccountNum&lt;br /&gt;    {&lt;br /&gt;        localVendTrans = VendTrans::find(localVendTransOpen.RefRecId);&lt;br /&gt;&lt;br /&gt;        specOffsetVoucher.create(localVendTransOpen.TableId,&lt;br /&gt;                                             localVendTransOpen.RecId,&lt;br /&gt;                                             localVendTransOpen.AmountCur,&lt;br /&gt;                                             localVendTrans.CurrencyCode);&lt;br /&gt;&lt;br /&gt;        settle.insert(localVendTransOpen.RecId,localVendTransOpen.AmountCur);&lt;br /&gt;&lt;br /&gt;        linesProcessed++;&lt;br /&gt;    }&lt;br /&gt;    ttscommit;&lt;br /&gt;&lt;br /&gt;    element.unLock();&lt;br /&gt;&lt;br /&gt;    //calculate totals for display&lt;br /&gt;    conSum = custVendSettle_Vend.openSumRemainAmount(common,currencyCode);&lt;br /&gt;    remainAmountCur = conpeek(conSum,1);&lt;br /&gt;    remainAmountMST = conpeek(conSum,2);&lt;br /&gt;    element.initCashDiscTotal();&lt;br /&gt;&lt;br /&gt;    element.initVendBalance();&lt;br /&gt;&lt;br /&gt;    //refresh the screen with the calculated totals&lt;br /&gt;    element.redraw();&lt;br /&gt;&lt;br /&gt;    //remove wait cursor&lt;br /&gt;    endLengthyOperation();&lt;br /&gt;&lt;br /&gt;    box::info(strfmt("%1 Vouchers Marked",linesProcessed));&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-6141483088675373669?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/6141483088675373669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/10/mark-all-for-open-cust-trans-and-open.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/6141483088675373669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/6141483088675373669'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/10/mark-all-for-open-cust-trans-and-open.html' title='Mark All for Open Cust Trans and Open Vend Trans'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-5145274491542539626</id><published>2010-10-13T16:00:00.003-04:00</published><updated>2010-10-13T16:05:00.713-04:00</updated><title type='text'>Large Inventory Close Workaround</title><content type='html'>&lt;b&gt;The Situation:&lt;/b&gt;&lt;br /&gt;We needed to inventory-close 18 months worth of transactions.&amp;nbsp; This happened because a legacy system was the system of record for this period of time and no one was worrying about details like inventory close.&amp;nbsp; When AX became the system of record, focus turned to reconciling accounts and the inventory close.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;We chose not to:&lt;/b&gt;&lt;br /&gt;We chose not to do the inventory close one month at a time because that would require opening old accounting periods.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Problem:&lt;/b&gt;&lt;br /&gt;When we did the inventory close for 18 months (moderate number of transactions), the process would run for 24 hours or so and then we would get an "Out of memory" error.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Workaround Attempts:&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The machines were reasonably powerful...but, just in case, we restarted the AOS and client to make sure that they were in the best condition possible.&amp;nbsp; No luck.&lt;/li&gt;&lt;li&gt;We used "Calculation Help" to try to spread out the load of the closing process among several work stations.&amp;nbsp; This shortened the 24 hours, but still ended in "Out of memory".&lt;/li&gt;&lt;li&gt;We set the Maximum Throughputs and Minimum... parameters to favor speed over accuracy.&amp;nbsp; For us, that was an option because this wasn't the system of record - we just need to get to a clean starting point. &lt;/li&gt;&lt;/ul&gt;&lt;b&gt;More Info:&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;When the inventory close failed, the status of the Invent Closing record was "Ledger Posting".&lt;/li&gt;&lt;li&gt;All of the inventory settlement records had been created (and didn't roll back) when the inventory close failed.&lt;/li&gt;&lt;li&gt;In looking at the code, it became clear the the "Calculation Help" only applied to creating/processing the inventory settlement records.&amp;nbsp; When it got to posting to the ledger, the original client was the only one doing the work.&lt;/li&gt;&lt;li&gt;In looking at the code, it seemed that Posting with a specification of Total, Item Group, or Item didn't change the transaction size.&amp;nbsp; We had a specification of 'Total'.&amp;nbsp; (that's the only one we tried)&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Our Plan:&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Create InventSettlement records.&amp;nbsp; We used the records created by one of our failed attempts, but you could also comment out the call to this.updateLedgerPosting(); towards the bottom of classes\InventCostHelp.run().&lt;/li&gt;&lt;li&gt;Create several InventClosing records with status of "Ledger Posting".&amp;nbsp; We created 3 total.&amp;nbsp; You can make these by commenting out some code in classes\InventCostHelp.run() after the inventClosing record is inserted but before any work is done.&lt;/li&gt;&lt;li&gt;Update InventSettlement.Voucher (in SQL Mgmt Studio) to match InventClosing.Voucher so that the InventSettlement records are assigned to the InventClosing records that you created in manageable chunks.&amp;nbsp; Since we were posting with a specification of 'Total' we just split the records roughly in thirds.&amp;nbsp; If you're posting by Item Group, you might want to take care to put all of the same item group in the same voucher.&lt;/li&gt;&lt;li&gt;Post each InventClosing record.&amp;nbsp; Normally, when an inventory close record has failed, all you can do is cancel it.&amp;nbsp; We temporarily commented code so that when we clicked Close on a failed record, it would 'pick up where it left off' and run updateLedgerPosting().&amp;nbsp; I've included some snippets below on this.&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;Result:&lt;/b&gt;&lt;br /&gt;Success! &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code related to step #4:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;classes\InventCostClosing&lt;br /&gt;&lt;br /&gt;static void main(Args args)&lt;br /&gt;{&lt;br /&gt;    InventClosing       inventClosing;&lt;br /&gt;    FormDataSource      fd;&lt;br /&gt;&lt;br /&gt;    InventCostClosing closing = InventCostClosing::newParameters();&lt;br /&gt;&lt;br /&gt;    //NDP 9/24/10 - BEGIN temp change&lt;br /&gt;    if (args &amp;amp;&amp;amp; args.caller() &amp;amp;&amp;amp; args.dataset() == tablenum(InventClosing))&lt;br /&gt;    {&lt;br /&gt;        inventClosing = args.record();&lt;br /&gt;    }&lt;br /&gt;    InventCostHelp::newInventClosing(inventClosing,true).run();&lt;br /&gt;    /*&lt;br /&gt;    if (! closing.prompt())&lt;br /&gt;        return;&lt;br /&gt;&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        closing.run();&lt;br /&gt;    }&lt;br /&gt;    catch&lt;br /&gt;    {&lt;br /&gt;        exceptionTextFallThrough();&lt;br /&gt;    }&lt;br /&gt;    */&lt;br /&gt;    //NDP 9/24/10 - END&lt;br /&gt;&lt;br /&gt;    if (args &amp;amp;&amp;amp; args.caller() &amp;amp;&amp;amp; args.dataset() == tablenum(InventClosing))&lt;br /&gt;    {&lt;br /&gt;...&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;classes\InventCostHelp&lt;br /&gt;&lt;br /&gt;public void run()&lt;br /&gt;{&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;    setprefix(InventCostClosing::prefixText(inventClosing.AdjustmentType));&lt;br /&gt;&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        this.progressInit(InventCostClosing::prefixText(inventClosing.AdjustmentType),inventClosing.CostNumOf,#AviUpdate);&lt;br /&gt;//NDP 9/24/10 - comment out starting here&lt;br /&gt;/*&lt;br /&gt;        if (! this.validate())&lt;br /&gt;            throw error("@SYS18447");&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        if (doMasterClient &amp;amp;&amp;amp; !trueClient)&lt;br /&gt;            masterClient = true;&lt;br /&gt;*/&lt;br /&gt;//NDP 9/24/10 - end comment out here&lt;br /&gt;        if (! doStop &amp;amp;&amp;amp; masterClient)&lt;br /&gt;        {&lt;br /&gt;            this.updateLedgerPosting();&lt;br /&gt;            if (inventClosing.RunRecalculation &amp;amp;&amp;amp; systemdateget() &amp;gt; inventClosing.TransDate)&lt;br /&gt;            {&lt;br /&gt;                this.runRecalculation();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Hope that helps,&lt;br /&gt;Nate&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-5145274491542539626?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/5145274491542539626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/10/large-inventory-close-workaround.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5145274491542539626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5145274491542539626'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/10/large-inventory-close-workaround.html' title='Large Inventory Close Workaround'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-2976266228286934715</id><published>2010-10-05T14:09:00.000-04:00</published><updated>2010-10-05T14:09:55.314-04:00</updated><title type='text'>Dynamics AX Technical Conference 2011</title><content type='html'>Registered!&amp;nbsp; Just in time for early-bird pricing.&amp;nbsp; Should be a great time!&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.microsoft.com/dynamics/DynamicsAXTechnicalConference2011/"&gt;&lt;img border="0" height="265" src="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-33-12-metablogapi/0827.HorizontalWebBanner_5F00_No1_5F00_v3_5F00_28D975EF.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-2976266228286934715?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/2976266228286934715/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/10/dynamics-ax-technical-conference-2011.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/2976266228286934715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/2976266228286934715'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/10/dynamics-ax-technical-conference-2011.html' title='Dynamics AX Technical Conference 2011'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-3286377349334805361</id><published>2010-09-22T09:47:00.001-04:00</published><updated>2010-09-22T09:47:40.686-04:00</updated><title type='text'>Purchase Order Print "Correct" Quantity</title><content type='html'>Standard AX functionality when printing an AP Purchase Order is to print the quantity of the Delivery Remainder (PurchLine.RemainPurchPhysical).&amp;nbsp; The Delivery Remainder is lowered as receipts are posted against the PO, so a PO that is printed after receipts have been posted can look confusing.&amp;nbsp; The PO will show a lower quantity and a lower dollar amount.&lt;br /&gt;&lt;br /&gt;You can add the following code to class/purchFormLetter.createParmLine to show to total quantity of the PO: the delivery remainder plus the qty already received.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;...&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;    [newPurchParmLine.ReceiveNow,  newPurchParmLine.RemainBefore      , newPurchParmLine.RemainAfter      ] = this.qtyPurch (_purchLine, naReal());&lt;br /&gt;    [newPurchParmLine.InventNow,   newPurchParmLine.RemainBeforeInvent, newPurchParmLine.RemainAfterInvent] = this.qtyInvent(_purchLine, naReal());&lt;br /&gt;}&lt;br /&gt;//existing code above&lt;br /&gt;&lt;br /&gt;//New Code: add the qty that was received already to the delivery remainder&lt;br /&gt;if (purchParmUpdate.SpecQty == PurchUpdate::All &amp;amp;&amp;amp; purchParmUpdate.DocumentStatus == DocumentStatus::PurchaseOrder)&lt;br /&gt;{&lt;br /&gt;    newPurchParmLine.ReceiveNow = _purchLine.RemainPurchPhysical + _purchLine.receivedInTotal();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-3286377349334805361?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/3286377349334805361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/09/purchase-order-print-correct-quantity.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/3286377349334805361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/3286377349334805361'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/09/purchase-order-print-correct-quantity.html' title='Purchase Order Print &quot;Correct&quot; Quantity'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-8890368397645531358</id><published>2010-07-14T13:40:00.001-04:00</published><updated>2010-07-14T13:41:55.593-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tips'/><title type='text'>Price Unit Excel Calculation</title><content type='html'>Here's the Excel calculation that I use when determining what Price Unit to use during imports/conversions to avoid loss of accuracy on small unit prices.&lt;br /&gt;&lt;br /&gt;Price Unit =POWER(10,MAX(LEN(A2) - FIND(".",A2) -2,0)) &lt;br /&gt;Price = A2*Price Unit&lt;br /&gt;(Where A2 is the original price, i.e. $0.0045) &lt;br /&gt;&lt;br /&gt;Everyone loves that Price Unit!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-8890368397645531358?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/8890368397645531358/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/07/price-unit-excel-calculation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/8890368397645531358'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/8890368397645531358'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/07/price-unit-excel-calculation.html' title='Price Unit Excel Calculation'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-5810339444406795095</id><published>2010-02-22T12:49:00.000-05:00</published><updated>2010-02-22T12:49:09.984-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><title type='text'>Image Resource can not be saved in temporary folder</title><content type='html'>We recently added a custom&amp;nbsp;image to a report.&amp;nbsp; To do this, we added a resource (AOT, Resources node) and put the following code in the executeSection method:&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; border-right: #999999 1px dashed; border-top: #999999 1px dashed; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; width: 100%;"&gt;&lt;code&gt;MyReportBitmapControl.imageName(SysResource::getImagePath("MyResourceName"));&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This worked find until we ran the report from a Menu Item.&amp;nbsp; Then we started to get an error that said "unable to save the data to c:\...\Temporary Internet Files\myResource.bmp".&lt;br /&gt;&lt;br /&gt;The issue ended up being that the Menu Item was set to Run On: Server.&amp;nbsp; When the Menu Item was set to Run On: Client, the problem was fixed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-5810339444406795095?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/5810339444406795095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/02/image-resource-can-not-be-saved-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5810339444406795095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5810339444406795095'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/02/image-resource-can-not-be-saved-in.html' title='Image Resource can not be saved in temporary folder'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-3568891026523506705</id><published>2010-02-17T11:30:00.001-05:00</published><updated>2010-02-17T11:30:44.624-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><title type='text'>Reset TTS Level to zero</title><content type='html'>When I executed an unbalanced transaction block, I use this code to get back to zero:&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; border-right: #999999 1px dashed; border-top: #999999 1px dashed; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; width: 100%;"&gt;&lt;code&gt;static void NDPToolsResetTTS(Args _args)&lt;br /&gt;{&lt;br /&gt;    while (appl.ttsLevel() &amp;gt; 0)&lt;br /&gt;    {&lt;br /&gt;        info(strfmt("Level %1 aborted",appl.ttsLevel()));&lt;br /&gt;        ttsAbort;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-3568891026523506705?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/3568891026523506705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/02/reset-tts-level-to-zero.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/3568891026523506705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/3568891026523506705'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/02/reset-tts-level-to-zero.html' title='Reset TTS Level to zero'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-6715569560897986065</id><published>2010-02-17T11:13:00.002-05:00</published><updated>2010-02-17T11:31:14.579-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><title type='text'>Find TableName from TableId</title><content type='html'>Sometimes I see a tableId in the data (i.e. in a refTableId field) and I wonder what table that is.&lt;br /&gt;&lt;br /&gt;I use this job to find it:&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; border-right: #999999 1px dashed; border-top: #999999 1px dashed; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; width: 100%;"&gt;&lt;code&gt;static void NDPToolsShowTableNameFromId(Args _args)&lt;br /&gt;{&lt;br /&gt;    SysDictTable sysDictTable;&lt;br /&gt;    int          id = 40015; //enter your ID here&lt;br /&gt;    ;&lt;br /&gt;    sysDictTable = new SysDictTable(id);&lt;br /&gt;    info (sysDictTable.name());&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-6715569560897986065?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/6715569560897986065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/02/find-tablename-from-tableid.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/6715569560897986065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/6715569560897986065'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/02/find-tablename-from-tableid.html' title='Find TableName from TableId'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-2090741308821662517</id><published>2010-02-12T14:55:00.005-05:00</published><updated>2010-02-17T11:20:48.664-05:00</updated><title type='text'>Date and Time in DAX</title><content type='html'>Just a quick example of the basic date and time functions.&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; border-right: #999999 1px dashed; border-top: #999999 1px dashed; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; width: 100%;"&gt;&lt;code&gt;static void time(Args _args)&lt;br /&gt;{&lt;br /&gt;    int                     t,h,m,s;&lt;br /&gt;    Date                    d;&lt;br /&gt;    InteropPermission       perm;&lt;br /&gt;    System.DateTime         dttime;&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;    //method #1&lt;br /&gt;    t = timenow();&lt;br /&gt;    d = systemDateGet(); //preferred to today()&lt;br /&gt;    h = trunc(t/3600);&lt;br /&gt;    m = trunc((t - h*3600)/60);&lt;br /&gt;    s = t - h*3600 - m * 60;&lt;br /&gt;    info (strfmt("%1 %2:%3:%4",d,h,strRFix(int2str(m),2,"0"),s));&lt;br /&gt;&lt;br /&gt;    //method #2&lt;br /&gt;    perm = new InteropPermission(InteropKind::ClrInterop);&lt;br /&gt;    perm.assert();&lt;br /&gt;    dttime = CLRInterop::staticInvoke("System.DateTime","get_Now" );&lt;br /&gt;    CodeAccessPermission::revertAssert();&lt;br /&gt;    info (dttime.ToString());&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&amp;nbsp;Notes: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;the DateTime type has the full array of .NET methods (i.e. ToShortTimeString, ToUniversalTime, etc)&lt;/li&gt;&lt;li&gt;systemDateGet() is affected by systemDateSet, making it superior in testing scenarios&lt;/li&gt;&lt;li&gt;strRFix is used to pad zeros onto single-digit minutes (i.e. 10:4 -&amp;gt; 10:04)&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-2090741308821662517?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/2090741308821662517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/02/date-and-time-in-dax.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/2090741308821662517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/2090741308821662517'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/02/date-and-time-in-dax.html' title='Date and Time in DAX'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-7803648833384964031</id><published>2010-02-02T16:14:00.004-05:00</published><updated>2010-08-24T07:17:02.945-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><title type='text'>Financial Statement Configuration Import/Export</title><content type='html'>To move Financial Statement Configuration between companies or environments:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Administration, Periodic, Data export/import, Definition Groups.&lt;/li&gt;&lt;li&gt;Create new definition group (type: standard)&lt;/li&gt;&lt;li&gt;Click 'Table Setup' button and add the tables listed below.&lt;/li&gt;&lt;li&gt;Click Export on the 'sending' system.&lt;/li&gt;&lt;li&gt;On the receiving system, choose Administration, Periodic, Data export/import, Import (you don't need the definition group)&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;The tables required are:&lt;/b&gt;&lt;br /&gt;DimensionSetTable&lt;br /&gt;DimensionSetRuleTable&lt;br /&gt;DimensionPriorityTable&lt;br /&gt;LedgerBalHeaderDim&lt;br /&gt;LedgerRowDef&lt;br /&gt;LedgerRowDefLine&lt;br /&gt;LedgerRowDefLineCalc&lt;br /&gt;LedgerBalColumnsDim&lt;br /&gt;&lt;br /&gt;Addition: as noted by the comment to this post, LedgerRowDefLine can be problematic to move because of the ParentRecId field.&amp;nbsp; The script below is one possible workaround.&amp;nbsp; Just make sure that you don't have any data in the SourceRecId field.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;static void NDPToolsPackRecId(Args _args)&lt;br /&gt;{&lt;br /&gt;    LedgerRowDefLine    ledgerRowDefLine, ledgerRowDefLineParent;&lt;br /&gt;    boolean             pack = true; //run with true before export.  run with false after import.&lt;br /&gt;    int                 i;&lt;br /&gt;&lt;br /&gt;    ;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;The script to 'pack/unpack' the recid was straight forward.  These are the steps to use it:&lt;br /&gt;&lt;br /&gt;   1. In this job, set the 'pack' variable to true and run the job prior to export in the source environment.&lt;br /&gt;   2. Do the export from the source environment using a standard definition group&lt;br /&gt;   3. Do the import in the destination environment.&lt;br /&gt;   4. In this job, set the 'pack' variable to false and run the job after import in the destination environment.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    ttsbegin;&lt;br /&gt;    if (pack)&lt;br /&gt;    {&lt;br /&gt;        while select forupdate ledgerRowDefLine&lt;br /&gt;        {&lt;br /&gt;            info (strfmt("%1 &amp;lt; %2",ledgerRowDefLine.SourceRecId,ledgerRowDefLine.RecId));&lt;br /&gt;            ledgerRowDefLine.SourceRecId = ledgerRowDefLine.RecId;&lt;br /&gt;            ledgerRowDefLine.update();&lt;br /&gt;            i++;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        while select forupdate ledgerRowDefLine where ledgerRowDefLine.ParentRecId != 0&lt;br /&gt;        {&lt;br /&gt;            select firstonly forupdate ledgerRowDefLineParent where ledgerRowDefLineParent.SourceRecId == ledgerRowDefLine.ParentRecId;&lt;br /&gt;            if (ledgerRowDefLineParent)&lt;br /&gt;            {&lt;br /&gt;                info (strfmt("%1 &amp;lt; %2",ledgerRowDefLine.ParentRecId,ledgerRowDefLineParent.RecId));&lt;br /&gt;                ledgerRowDefLine.ParentRecId = ledgerRowDefLineParent.RecId;&lt;br /&gt;                ledgerRowDefLine.update();&lt;br /&gt;&lt;br /&gt;                //clear the temporary storage location.&lt;br /&gt;                ledgerRowDefLineParent.SourceRecId = 0;&lt;br /&gt;                ledgerRowDefLineParent.update();&lt;br /&gt;&lt;br /&gt;                i++;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    ttscommit;&lt;br /&gt;    info (strfmt("%1 records updated",i));&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-7803648833384964031?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/7803648833384964031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/02/importexport-financial-statement.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/7803648833384964031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/7803648833384964031'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/02/importexport-financial-statement.html' title='Financial Statement Configuration Import/Export'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-3233836730826646516</id><published>2010-01-29T09:02:00.001-05:00</published><updated>2010-01-29T09:04:33.012-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><title type='text'>Bitmaps in Reports</title><content type='html'>One&amp;nbsp;way to add 'custom' images in an AX report is to:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add the image as a resource in the AOT, Resources node (right click, Create from File)&lt;/li&gt;&lt;li&gt;In the report, Add a Bitmap control and set AutoDeclaration to Yes.&lt;/li&gt;&lt;li&gt;In the report, sometime prior to the rendering of the bitmap (i.e. executeSection prior to super), code: &lt;/li&gt;&lt;/ol&gt;&lt;pre style="background-color: #eeeeee; border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; border-right: #999999 1px dashed; border-top: #999999 1px dashed; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; width: 100%;"&gt;&lt;code&gt;myBitmapControl.imageName(SysResource::getImagePath("myresourcename"));&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-3233836730826646516?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/3233836730826646516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/01/bitmaps-in-reports.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/3233836730826646516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/3233836730826646516'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/01/bitmaps-in-reports.html' title='Bitmaps in Reports'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-5457956130159342368</id><published>2010-01-28T07:23:00.002-05:00</published><updated>2010-01-29T09:17:47.868-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Fun'/><title type='text'>Tetris</title><content type='html'>This morning I stumbled upon Tetris in standard AX.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_5AVFZZy80To/S2LpOaUC-DI/AAAAAAAAABk/RMkxncpGOwQ/s1600-h/ScreenShot053.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" kt="true" src="http://4.bp.blogspot.com/_5AVFZZy80To/S2LpOaUC-DI/AAAAAAAAABk/RMkxncpGOwQ/s200/ScreenShot053.jpg" width="149" /&gt;&lt;/a&gt;&lt;/div&gt;Check out the form: tutorial_Tetris.&lt;br /&gt;&lt;br /&gt;Good for a smile. :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-5457956130159342368?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/5457956130159342368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/01/tetris.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5457956130159342368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5457956130159342368'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/01/tetris.html' title='Tetris'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_5AVFZZy80To/S2LpOaUC-DI/AAAAAAAAABk/RMkxncpGOwQ/s72-c/ScreenShot053.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-5867205386800157280</id><published>2010-01-19T08:13:00.000-05:00</published><updated>2010-01-19T08:13:35.324-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Tips'/><title type='text'>Grid column reorder problem</title><content type='html'>IntelliMorph lets users re-order (move) grid columns.&amp;nbsp; If you try to drag and drop a grid column but it won't drag, you might be overriding the tabChanged method on your tab control.&amp;nbsp; For some reason, overriding this method kills the ability to re-order columns.&amp;nbsp; Instead, you might override the individual tabPage control pageActivated methods.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_5AVFZZy80To/S1Wu_6zmqpI/AAAAAAAAABc/gK-SkZ53jIA/s1600-h/ScreenShot049.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" ps="true" src="http://1.bp.blogspot.com/_5AVFZZy80To/S1Wu_6zmqpI/AAAAAAAAABc/gK-SkZ53jIA/s320/ScreenShot049.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Also, you need to have AllowUserSetup set to Yes on the form Design, but that's a bit more obvious.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-5867205386800157280?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/5867205386800157280/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/01/grid-column-reorder-problem.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5867205386800157280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5867205386800157280'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/01/grid-column-reorder-problem.html' title='Grid column reorder problem'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_5AVFZZy80To/S1Wu_6zmqpI/AAAAAAAAABc/gK-SkZ53jIA/s72-c/ScreenShot049.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-8514327820585740905</id><published>2010-01-19T07:41:00.002-05:00</published><updated>2010-01-19T07:52:33.176-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tips'/><title type='text'>Record Filter or Query Range values</title><content type='html'>&lt;strong&gt;A nice article covering how to filter records in AX&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://axassociate.blogspot.com/2007/12/filtering-record-in-dynamics-ax.html"&gt;http://axassociate.blogspot.com/2007/12/filtering-record-in-dynamics-ax.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Not specifically covered in the article&lt;/strong&gt;&lt;br /&gt;Filter for&amp;nbsp;blanks: ""&lt;br /&gt;Filter for&amp;nbsp;non-blanks: !""&lt;br /&gt;Filter for checkbox checked: 1&lt;br /&gt;Filter for checkbox unchecked: 0&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-8514327820585740905?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/8514327820585740905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/01/dynamics-ax-filter-or-range-values.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/8514327820585740905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/8514327820585740905'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/01/dynamics-ax-filter-or-range-values.html' title='Record Filter or Query Range values'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-7060542203876864975</id><published>2010-01-14T07:20:00.002-05:00</published><updated>2010-01-14T08:38:05.565-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><title type='text'>SQL Query to Move Definition Groups</title><content type='html'>It's &lt;strong&gt;not&lt;/strong&gt; possible to use Definition Groups (&lt;em&gt;Admin,Periodic,Data Export/Import, Definition Groups&lt;/em&gt;)&amp;nbsp;to&amp;nbsp;move data held in &lt;strong&gt;shared&lt;/strong&gt; tables.&amp;nbsp;&amp;nbsp;So, here's the quick and dirty sql query that I use&amp;nbsp;(in SQL Server Management Studio) to do the job.&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; border-right: #999999 1px dashed; border-top: #999999 1px dashed; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; width: 100%;"&gt;&lt;code&gt;DECLARE @GroupId AS varchar(20)&lt;br /&gt;&lt;br /&gt;SET @GroupId = 'FA1' --set this to your Definition Group ID&lt;br /&gt;&lt;br /&gt;--change all 8 database names to match your environments&lt;br /&gt;INSERT INTO AX42_DB_TEST.dbo.sysExpImpGroup SELECT * FROM AX42_DB_DEV.dbo.sysExpImpGroup WHERE groupId = @GroupId&lt;br /&gt;INSERT INTO AX42_DB_TEST.dbo.sysExpImpTable SELECT * FROM AX42_DB_DEV.dbo.sysExpImpTable WHERE groupId = @GroupId&lt;br /&gt;INSERT INTO AX42_DB_TEST.dbo.sysExpImpField SELECT * FROM AX42_DB_DEV.dbo.sysExpImpField WHERE groupId = @GroupId&lt;br /&gt;INSERT INTO AX42_DB_TEST.dbo.sysExpImpTableQuery SELECT * FROM AX42_DB_DEV.dbo.sysExpImpTableQuery WHERE groupId = @GroupId&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;I've also read that when you use standard Data Export/Import move a definition group itself, CRs are stripped out of your conversion code. (&lt;a href="http://gotdax.blogspot.com/2009/12/dynamics-ax-import-export-tool-digging.html"&gt;http://gotdax.blogspot.com/2009/12/dynamics-ax-import-export-tool-digging.html&lt;/a&gt;) This gets around that problem as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-7060542203876864975?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/7060542203876864975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/01/sql-query-to-move-definition-groups.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/7060542203876864975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/7060542203876864975'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/01/sql-query-to-move-definition-groups.html' title='SQL Query to Move Definition Groups'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-1712147166241546647</id><published>2010-01-13T11:12:00.009-05:00</published><updated>2010-01-13T11:43:58.172-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Fixed Assets'/><title type='text'>How to Load Fixed Assets</title><content type='html'>&lt;strong&gt;Task&lt;/strong&gt;: load about 2000 fixed assets into Dynamics AX 4.0.&amp;nbsp; Some assets have been previously scrapped, sold, and fully depreciated.&amp;nbsp; Otherwise, the assets are generally part way through straight-line depreciation.&amp;nbsp; Assets fall into 6 groups (i.e. buildings, machinery, etc.) and need to be associated with a financial dimension indicating the department (i.e. shipping, production, etc.).&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Minimum Data that you need to import...and where it maps to in AX)&lt;/strong&gt;&lt;br /&gt;Fixed Asset Number&amp;nbsp; (AssetTable.AssetId, AssetBook.AssetId)&lt;br /&gt;Asset Name (AssetTable.Name)&lt;br /&gt;Asset Group (AssetTable.AssetGroup, AssetBook.AssetGroup)&lt;br /&gt;Placed in Service Date (AssetBook.AcquisitionDate, AssetTable.GuaranteeDate) - GuaranteeDate is temporary, use whatever field you like&lt;br /&gt;Aquisition Price (AssetBook.AcquisitionPrice)&lt;br /&gt;Service Life in Years (AssetBook.ServiceLife)&lt;br /&gt;Service Life in Months (AssetBook.LifeTime) - I could have calculated this during import&lt;br /&gt;Depreciation Periods Remaining (AssetBook.LifeTimeRest)&lt;br /&gt;Accumulated depreciation&amp;nbsp;from legacy system&amp;nbsp;(AssetTable.AssetReplaceCost) - this is temporary, use whatever field you like&lt;br /&gt;&lt;em&gt;plus other data that you may or may not have&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 1 - Import&lt;/strong&gt;&lt;br /&gt;Define custom definition group for AssetTable and AssetBook.&amp;nbsp; Field setup as described above.&lt;br /&gt;(Administration, Periodic, Data Export/Import, Definition Groups)&lt;br /&gt;&lt;img border="0" ps="true" src="http://2.bp.blogspot.com/_5AVFZZy80To/S0zj_4hUdFI/AAAAAAAAABI/rx91x9YX3xM/s640/ScreenShot010.jpg" /&gt;&lt;br /&gt;I used the Conversion tab to set some values:&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; border-right: #999999 1px dashed; border-top: #999999 1px dashed; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; width: 100%;"&gt;&lt;code&gt;AssetBook book;&lt;br /&gt;;&lt;br /&gt;book.data(assetBook);&lt;br /&gt;book.BookId = 'OurBookId';&lt;br /&gt;book.PostingProfile = 'OurPostingProfileId';&lt;br /&gt;book.Depreciation = NoYes::Yes;&lt;br /&gt;book.LastDepreciationDate = mkDate(31,10,2009);&lt;br /&gt;book.DepreciationConvention = AssetDepreciationConvention::MidMonth1st;&lt;br /&gt;assetBook.data(book);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Note: the LastDepreciationDate is the date that accumulated depreciation was calculated through in the legacy system.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 2 - Post Journal for Acquisition&lt;/strong&gt;&lt;br /&gt;Once you have the Fixed Asset records that you imported in step 1, you will see that they have the status 'Not yet acquired'.&amp;nbsp; To properly record the aquisition, you have to post a Fixed Asset acquisition&amp;nbsp;journal.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;In our case, the Ledger balances already reflected the prior purchase of the assets.&amp;nbsp; We needed to record the acquisition, but didn't want it to affect our ledger balances.&amp;nbsp; The simple work-around was to temporarily set the aquisition ledger account &lt;em&gt;and&lt;/em&gt; offset account to the same ledger account so there is no net affect.&amp;nbsp; (GL, Setup, Fixed Assets, Posting Profiles)&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_5AVFZZy80To/S0zp4JLqOwI/AAAAAAAAABQ/om1xxwPyF2A/s1600-h/ScreenShot011.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" ps="true" src="http://1.bp.blogspot.com/_5AVFZZy80To/S0zp4JLqOwI/AAAAAAAAABQ/om1xxwPyF2A/s320/ScreenShot011.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;It's possible to use Proposal &amp;gt; Acquisition&amp;nbsp;to create lines in the Fixed Asset journal and then change the dates* on all the lines (they are defaulted to the acquisition date - but those periods were closed for us).&amp;nbsp; Instead, I wrote a little job to create the journals.&amp;nbsp; (see below)&lt;br /&gt;*when you change this date, the AssetBook.AcquisitionDate is overwritten.&amp;nbsp; see solution below.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 3 - Post Journal for (legacy system) Accumulated Depreciation&lt;/strong&gt;&lt;br /&gt;Since most of our fixed assets were partially depreciated at the time of import, we needed some way to record the prior depreciation.&amp;nbsp; To do this you could use Proposal &amp;gt; Depreciation to get 'caught up'.&amp;nbsp; There are two small issues: 1) if acquisition date was changed during step 2, the depreciation proposal will not know the correct aquisition date.&amp;nbsp; 2) in our case, again, the Ledger balances already reflected the depreciation prior to import.&lt;br /&gt;Our solution was&amp;nbsp;to create a Depreciation Adjustment journal that has a matching ledger account and offset account.&amp;nbsp; Since there isn't a Proposal &amp;gt; Depreciation Adjustment, I wrote&amp;nbsp;a job to do this.&amp;nbsp; (see below)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 4 - Ready To Go&lt;/strong&gt;&lt;br /&gt;The key fields that allow depreciation to 'pick up where it left off' are AssetBook.LifeTimeRest (remaining depreciation periods) and AssetBook.LastDepreciationDate.&amp;nbsp; We set these during the import, so there shouldn't be anything further to do.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Our Journal Creation Job&lt;/strong&gt;&lt;br /&gt;As noted in Step 2 and 3 - we used a job to create the acquisition journal and&amp;nbsp;depreciation adjustment journal.&amp;nbsp; Here it is:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; border-right: #999999 1px dashed; border-top: #999999 1px dashed; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; width: 100%;"&gt;&lt;code&gt;static void AssetCreateJournal(Args _args)&lt;br /&gt;{&lt;br /&gt;    LedgerJournalName   ledgerJournalName;&lt;br /&gt;    LedgerJournalTable  ledgerJournalTable;&lt;br /&gt;    LedgerJournalTrans  ledgerJournalTrans;&lt;br /&gt;    NumberSeq           numberSeq;&lt;br /&gt;    AssetTable          assetTable;&lt;br /&gt;    AssetBook           assetBook;&lt;br /&gt;    int                 lineNum;&lt;br /&gt;    Date                transDate;&lt;br /&gt;    ;&lt;br /&gt;&lt;br /&gt;    transDate = mkDate(31,10,2009);  //Oct 31, 2009 = our conversion date&lt;br /&gt;&lt;br /&gt;    ttsbegin;&lt;br /&gt;&lt;br /&gt;    //Record the acquisition&lt;br /&gt;    select firstonly ledgerjournalName where ledgerJournalName.JournalName == 'OurJournalName';&lt;br /&gt;    ledgerJournalTable.JournalName = LedgerJournalName.JournalName;&lt;br /&gt;    ledgerJournalTable.initFromLedgerJournalName();&lt;br /&gt;    ledgerJournalTable.insert();&lt;br /&gt;&lt;br /&gt;    numberSeq = NumberSeq::newGetVoucherFromCode(ledgerJournalName.VoucherSeries);&lt;br /&gt;&lt;br /&gt;    while select assetBook where assetBook.Status == AssetStatus::NoAcquisition&lt;br /&gt;    {&lt;br /&gt;        lineNum++;&lt;br /&gt;        ledgerJournalTrans.clear();&lt;br /&gt;        ledgerJournalTrans.voucher = numberSeq.voucher();&lt;br /&gt;        ledgerJournalTrans.LineNum = lineNum;&lt;br /&gt;        ledgerJournalTrans.TransDate = transDate;&lt;br /&gt;        ledgerJournalTrans.JournalNum = ledgerJournalTable.JournalNum;&lt;br /&gt;        ledgerJournalTrans.initValue();  //sets currencyCode and exchRate, etc&lt;br /&gt;        ledgerJournalTrans.AccountType = LedgerJournalACType::FixedAssets;&lt;br /&gt;        ledgerJournalTrans.AccountNum = assetBook.AssetId;&lt;br /&gt;        ledgerJournalTrans.initAssetBookid();  //sets assetBookId&lt;br /&gt;        ledgerJournalTrans.initAssetPostingProfile(); //sets postingProfile&lt;br /&gt;        ledgerJournalTrans.Txt = "Acquisition";&lt;br /&gt;        ledgerJournalTrans.AssetTransType = AssetTransTypeJournal::Acquisition;&lt;br /&gt;        ledgerJournalTrans.AmountCurDebit = assetBook.AcquisitionPrice;&lt;br /&gt;        ledgerJournalTrans.OffsetAccountType = LedgerJournalACType::Ledger;&lt;br /&gt;        ledgerJournalTrans.OffsetAccount = ledgerJournalTrans.findOffsetAccount();&lt;br /&gt;        ledgerJournalTrans.Dimension = assetBook.Dimension;&lt;br /&gt;        ledgerJournalTrans.insert();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    ttscommit;&lt;br /&gt;    info (strfmt("Fixed Asset Journal %1 was created with %2 lines",ledgerJournalTable.JournalNum,lineNum));&lt;br /&gt;&lt;br /&gt;    ttsbegin;&lt;br /&gt;&lt;br /&gt;    //Now do the same thing for depreciation adjustment&lt;br /&gt;    lineNum = 0;&lt;br /&gt;&lt;br /&gt;    select firstonly ledgerjournalName where ledgerJournalName.JournalName == 'FA';&lt;br /&gt;    ledgerJournalTable.clear();&lt;br /&gt;    ledgerJournalTable.JournalName = LedgerJournalName.JournalName;&lt;br /&gt;    ledgerJournalTable.initFromLedgerJournalName();&lt;br /&gt;    ledgerJournalTable.insert();&lt;br /&gt;&lt;br /&gt;    numberSeq = NumberSeq::newGetVoucherFromCode(ledgerJournalName.VoucherSeries);&lt;br /&gt;&lt;br /&gt;    //during import, the accumulated depreciation was temporarily stored in the assetReplaceCost field&lt;br /&gt;    while select assetTable where assetTable.AssetReplaceCost &amp;gt; 0&lt;br /&gt;    {&lt;br /&gt;        lineNum++;&lt;br /&gt;        ledgerJournalTrans.clear();&lt;br /&gt;        ledgerJournalTrans.voucher = numberSeq.voucher();&lt;br /&gt;        ledgerJournalTrans.LineNum = lineNum;&lt;br /&gt;        ledgerJournalTrans.TransDate = transDate;&lt;br /&gt;        ledgerJournalTrans.JournalNum = ledgerJournalTable.JournalNum;&lt;br /&gt;        ledgerJournalTrans.initValue();  //sets currencyCode and exchRate, etc&lt;br /&gt;        ledgerJournalTrans.AccountType = LedgerJournalACType::FixedAssets;&lt;br /&gt;        ledgerJournalTrans.AccountNum = assetTable.AssetId;&lt;br /&gt;        ledgerJournalTrans.initAssetBookid();  //sets assetBookId&lt;br /&gt;        ledgerJournalTrans.initAssetPostingProfile(); //sets postingProfile&lt;br /&gt;        ledgerJournalTrans.Txt = strfmt("Depreciation through %1",transDate);&lt;br /&gt;        ledgerJournalTrans.AssetTransType = AssetTransTypeJournal::DepreciationAdj;&lt;br /&gt;        ledgerJournalTrans.AmountCurCredit = assetTable.AssetReplaceCost; //using our temporary data from import&lt;br /&gt;        ledgerJournalTrans.OffsetAccountType = LedgerJournalACType::Ledger;&lt;br /&gt;        ledgerJournalTrans.OffsetAccount = ledgerJournalTrans.findOffsetAccount();&lt;br /&gt;        ledgerJournalTrans.Dimension = AssetBook::Find(ledgerJournalTrans.AccountNum,ledgerJournalTrans.AssetBookId).Dimension;&lt;br /&gt;        ledgerJournalTrans.insert();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    ttscommit;&lt;br /&gt;&lt;br /&gt;    info (strfmt("Fixed Asset Journal %1 was created with %2 lines",ledgerJournalTable.JournalNum,lineNum));&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;After reviewing and posting the journals, we ran the following job to clean up the records - remove temporary data and fix the aquisition date.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; border-right: #999999 1px dashed; border-top: #999999 1px dashed; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; width: 100%;"&gt;&lt;code&gt;static void AssetFinalizeImport(Args _args)&lt;br /&gt;{&lt;br /&gt;    AssetTable          assetTable;&lt;br /&gt;    AssetBook           assetBook;&lt;br /&gt;    ;&lt;br /&gt;&lt;br /&gt;    ttsbegin;&lt;br /&gt;&lt;br /&gt;    //during import, the accumulated depreciation was temporarily stored in the assetReplaceCost field&lt;br /&gt;    while select forupdate assetTable&lt;br /&gt;    {&lt;br /&gt;        assetBook = AssetBook::Find(assetTable.AssetId,'OurBookId',true);&lt;br /&gt;&lt;br /&gt;        if (assetBook)&lt;br /&gt;        {&lt;br /&gt;            if (assetTable.GuaranteeDate != dateNull())&lt;br /&gt;            {&lt;br /&gt;                assetBook.AcquisitionDate = assetTable.GuaranteeDate;&lt;br /&gt;            }&lt;br /&gt;            //if fully depreciated&lt;br /&gt;            if (assetTable.AssetReplaceCost == assetBook.AcquisitionPrice)&lt;br /&gt;            {&lt;br /&gt;                assetBook.Status = AssetStatus::Closed;&lt;br /&gt;            }&lt;br /&gt;            assetBook.update();&lt;br /&gt;&lt;br /&gt;            //clear the temporary fields&lt;br /&gt;            assetTable.AssetReplaceCost = 0;&lt;br /&gt;            assetTable.GuaranteeDate = datenull();&lt;br /&gt;            assetTable.update();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    ttscommit;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;That's all - hope it's a help.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-1712147166241546647?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/1712147166241546647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/01/how-to-load-fixed-assets.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/1712147166241546647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/1712147166241546647'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/01/how-to-load-fixed-assets.html' title='How to Load Fixed Assets'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_5AVFZZy80To/S0zj_4hUdFI/AAAAAAAAABI/rx91x9YX3xM/s72-c/ScreenShot010.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-4664085963973230216</id><published>2010-01-12T11:41:00.003-05:00</published><updated>2010-01-13T11:39:47.036-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AX 4.0'/><title type='text'>Data Import Conversion</title><content type='html'>The&amp;nbsp;'trick' to placing code in the conversion tab of a Definition Group is to define a second table buffer and&amp;nbsp;using the .data() method to copy the date back and forth.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_5AVFZZy80To/S0ymQEX9TNI/AAAAAAAAABA/Soh0Kb1nxsk/s1600-h/ScreenShot009.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" ps="true" src="http://4.bp.blogspot.com/_5AVFZZy80To/S0ymQEX9TNI/AAAAAAAAABA/Soh0Kb1nxsk/s640/ScreenShot009.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-4664085963973230216?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/4664085963973230216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2010/01/data-import-conversion.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/4664085963973230216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/4664085963973230216'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2010/01/data-import-conversion.html' title='Data Import Conversion'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_5AVFZZy80To/S0ymQEX9TNI/AAAAAAAAABA/Soh0Kb1nxsk/s72-c/ScreenShot009.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-2641046835138170325</id><published>2009-12-31T10:00:00.008-05:00</published><updated>2010-01-13T11:40:43.053-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSRS'/><title type='text'>Database fields in SSRS page header</title><content type='html'>&lt;strong&gt;Scenario&lt;/strong&gt;&lt;br /&gt;A&amp;nbsp;financial report that I'm writing has columns for current year, prior year, etc.&amp;nbsp; The dates that define the columns are calculated based on the users entry of a report parameter date.&amp;nbsp; (i.e. current year start = January 1st of the year of the report parameter date).&amp;nbsp; These dates were declared and calculated&amp;nbsp;in a dataset query and then used as parameters in the TSQL query.&amp;nbsp; This worked fine.&amp;nbsp; I ran into some trouble when I wanted to display the calculated dates in the header of the report.&amp;nbsp; We're using SQL Server 2005 and Visual Studio 2005.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;What DID work&lt;/strong&gt;&lt;br /&gt;1. Create a dataset to calculate the dates based on the report parameters.&amp;nbsp; Select the calculated values into a table.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_5AVFZZy80To/Szy6jIwd3XI/AAAAAAAAAAM/UdfTrRrHMH8/s1600-h/ScreenShot001.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" ps="true" src="http://4.bp.blogspot.com/_5AVFZZy80To/Szy6jIwd3XI/AAAAAAAAAAM/UdfTrRrHMH8/s640/ScreenShot001.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;2. Create an internal report parameter for each calculated date and set the available values and default value based on the dataset above.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_5AVFZZy80To/Szy7TVDeP3I/AAAAAAAAAAU/3joBqSNYOJw/s1600-h/ScreenShot003.jpg" imageanchor="1" style="cssfloat: left; margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" ps="true" src="http://2.bp.blogspot.com/_5AVFZZy80To/Szy7TVDeP3I/AAAAAAAAAAU/3joBqSNYOJw/s400/ScreenShot003.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;3. These internal report parameters can be used in other dataset queries and in the report header.&lt;br /&gt;What I could have done but didn't want to&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;strong&gt;What I could have done but didn't want to&lt;/strong&gt;&lt;br /&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;I could have rewritten the TSQL that calculated the dates in an expression within the report...but didn't want duplicate code.&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;What didn't work&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The date variables that I declared in TSQL were not accessible to the report fields&lt;/li&gt;&lt;li&gt;I tried declaring internal and/or hidden report parameters and setting their values in TSQL. I couldn't find a combination of settings that allowed me to set the value of the report parameters&lt;/li&gt;&lt;li&gt;I tried creating a second dataset that calculated my dates and returned them as a single-row. This seemed promising, but for some reason SSRS restricts referencing fields in the report header. That's a strange one. I read several articles indicating that you can get around this issue by putting a hidden field in the body of the report...and then doing 4 other goofy workarounds to make it consistently available on multi-page reports...yuk.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-2641046835138170325?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/2641046835138170325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2009/12/showing-database-fields-in-report.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/2641046835138170325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/2641046835138170325'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2009/12/showing-database-fields-in-report.html' title='Database fields in SSRS page header'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_5AVFZZy80To/Szy6jIwd3XI/AAAAAAAAAAM/UdfTrRrHMH8/s72-c/ScreenShot001.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-1068609359214494233</id><published>2009-12-17T14:45:00.031-05:00</published><updated>2011-01-11T11:06:04.323-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Certification'/><title type='text'>Microsoft Certifications</title><content type='html'>Microsoft learning catalog, including exams for&amp;nbsp;MS Dynamics AX:&lt;br /&gt;&lt;a href="http://learning.microsoft.com/Manager/Catalog.aspx"&gt;http://learning.microsoft.com/Manager/Catalog.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Clear summary of MCBMSP for Dynamics AX&lt;br /&gt;&lt;a href="http://www.colaboy.co.uk/Default.aspx?story=448"&gt;http://www.colaboy.co.uk/Default.aspx?story=448&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Example of MCBMSP - Development for Dynamics AX&lt;br /&gt;&lt;a href="http://community.dynamics.com/blogs/axdilip/archive/tags/Certification/default.aspx"&gt;http://community.dynamics.com/blogs/axdilip/archive/tags/Certification/default.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Advice after taking the required exams&lt;br /&gt;&lt;a href="http://axstart.spaces.live.com/Blog/cns%21E82F2C8CB173C0A0%21455.entry"&gt;http://axstart.spaces.live.com/Blog/cns!E82F2C8CB173C0A0!455.entry&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Notes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It seems that MCBMSP (MS Cert. Business Mgmt. Solutions Professional)&amp;nbsp;is a flavor of MCITP (MS Cert. IT Professional).&amp;nbsp; I believe the broadest credential for this is MCP (MS Cert. Professional).&lt;/li&gt;&lt;li&gt;After the first exam&amp;nbsp;toward MCBMSP, you become an MCBMSS (MS Cert. Business Mgmt. Solutions Specialist).&amp;nbsp; The broadest credential for this is MCTS (MS Cert. Technology Specialist) - so you'd put MCTS on your business card, not MCBMSS. That good - 6 characters is a bit steep!&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Update 1/6/10&lt;/b&gt;: Passed MB6-819.&amp;nbsp; 86%&amp;nbsp; This was my first MS exam and I'm impressed that it was fair and balanced - not too easy, not too hard.&amp;nbsp; They give you an overall score, and also a score in each topic area.&amp;nbsp; I actually did worse on the more basic topics.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update 12/6/10&lt;/b&gt;: Passed MB6-821 (AX 2009 MorphX Solution Development).&amp;nbsp; I think Financials (MB6-818) will be next.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update 1/11/11&lt;/b&gt;: Passed MB6-818 (AX 2009 Financials)&amp;nbsp; Next up: MB6-820 (Install/Config) which is looking pretty short!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-1068609359214494233?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/1068609359214494233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2009/12/microsoft-certifications.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/1068609359214494233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/1068609359214494233'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2009/12/microsoft-certifications.html' title='Microsoft Certifications'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-2535097968169934232</id><published>2009-12-16T08:03:00.007-05:00</published><updated>2011-02-21T09:23:04.348-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Documentation'/><title type='text'>Development Documentation</title><content type='html'>There are several repositories that I use&amp;nbsp;for Dynamics AX development documentation:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;MSDN&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa546389%28v=MSDN.10%29.aspx"&gt;&lt;/a&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc678142.aspx"&gt;http://msdn.microsoft.com/en-us/library/cc678142.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Axaptapedia&lt;/b&gt;&lt;br /&gt;&lt;a href="http://www.axaptapedia.com/Main_Page"&gt;http://www.axaptapedia.com/Main_Page&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Microsoft's main Dynamics AX Page&lt;/b&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/dynamics/ax/default.aspx"&gt;http://msdn.microsoft.com/en-us/dynamics/ax/default.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Microsoft's Dynamics AX Forum&lt;/b&gt;&lt;br /&gt;&lt;a href="http://community.dynamics.com/forums/33.aspx"&gt;http://community.dynamics.com/forums/33.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sunrise Technologies Functional Demos &lt;/b&gt;&lt;br /&gt;&lt;a href="http://www.sunriseconsult.com/FunctionalDemos.aspx"&gt;http://www.sunriseconsult.com/FunctionalDemos.aspx&amp;nbsp;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Dynamics AX videos by Saveen Reddy&lt;br /&gt;&lt;a href="http://www.vimeo.com/tag:dynamicsax"&gt;http://www.vimeo.com/tag:dynamicsax &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-2535097968169934232?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/2535097968169934232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2009/12/development-documentation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/2535097968169934232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/2535097968169934232'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2009/12/development-documentation.html' title='Development Documentation'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-5691699917849360039</id><published>2009-12-15T12:48:00.007-05:00</published><updated>2010-01-19T08:15:13.212-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><title type='text'>Tools</title><content type='html'>There are several tools that I find useful almost every day:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Gadwin Printscreen&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://www.gadwin.com/printscreen/"&gt;http://www.gadwin.com/printscreen/&lt;/a&gt;&lt;br /&gt;There is a free version.&amp;nbsp; I set it to capture a 'Rectagular Area' to the clipboard.&amp;nbsp; Wonderful.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Cute PDF&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://www.cutepdf.com/"&gt;http://www.cutepdf.com/&lt;/a&gt;&lt;br /&gt;A free PDF writer that's always worked well for me.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Dynamics AX Task Recorder&lt;/strong&gt;&lt;br /&gt;Available from MS PartnerSource.&amp;nbsp; An amazingly easy way to create user documenation for AX.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Dynamics AX 2009 Keyboard Shortcuts&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://kashperuk.blogspot.com/2008/07/microsoft-dynamics-ax-2009-keyboard.html"&gt;http://kashperuk.blogspot.com/2008/07/microsoft-dynamics-ax-2009-keyboard.html&lt;/a&gt;&lt;br /&gt;I'm not sure who wrote this document, but it was a big help to me.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Format source code for blog posting&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://formatmysourcecode.blogspot.com/"&gt;http://formatmysourcecode.blogspot.com/&lt;/a&gt;&lt;br /&gt;Just right.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-5691699917849360039?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/5691699917849360039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2009/12/tools.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5691699917849360039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5691699917849360039'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2009/12/tools.html' title='Tools'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4865774416414395121.post-5440471442249483996</id><published>2009-12-15T12:35:00.002-05:00</published><updated>2009-12-15T12:39:41.209-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Multi-AOS'/><title type='text'>Multiple AOS Environment</title><content type='html'>Recently I've been working on a site with 3 production AOSs.&amp;nbsp; Code updates were a hassle because we would have to restart each AOS after importing the new code.&amp;nbsp; The following post shares a method to solve this problem and it's worked great for us.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://dynamics-ax.blogspot.com/2006/04/flush-aos-cache-from-code.html"&gt;http://dynamics-ax.blogspot.com/2006/04/flush-aos-cache-from-code.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4865774416414395121-5440471442249483996?l=natepaine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://natepaine.blogspot.com/feeds/5440471442249483996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://natepaine.blogspot.com/2009/12/multiple-aos-environment.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5440471442249483996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4865774416414395121/posts/default/5440471442249483996'/><link rel='alternate' type='text/html' href='http://natepaine.blogspot.com/2009/12/multiple-aos-environment.html' title='Multiple AOS Environment'/><author><name>Nate Paine</name><uri>http://www.blogger.com/profile/10790308403996977217</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
