Monday, December 31, 2012

Q1 2013 Hotel Promotions

Here are some Q1 2013 hotel promotions and info about them. I didn't find anything like this online so here it is from my researching. It's a mediocre quarter. I'm staying at Hiltons and jumping the Marriotts for 6 stays to max out the 3 free cat 1-4 stays. I might do the Starwood one for a few weeks but I haven't decided yet...


Hilton Q1 2013 promotion - Double Your HHonors
Valid January 7th - March 31st
Earn double points or double miles (pick one or the other and cannot change once selected).
  • Earn double points or double miles
  • No limit to points
  • 1 in 5 Hilton hotels are NOT participating  (non-participating hotels)
This promotion is mediocre. Its not as good in comparison with the other ones like 4 stays = 1 free night at any Hilton or the triple points promos.

Note: If you want to rack up the airline miles, I would suggest hopping hotels during the week and set your Hilton double dip preferences to Points and Fixed Miles. That gives you 500 miles per stay (1000 with this promotion). If staying 3 nights on a standard travel week, you can get 3000 miles on your selected airline. Pretty nice but the miles was the same as Q4 2012 so I'm not too excited.

Marriott Q1 2013 promotion - Marriott MegaBonus 2013
Valid February 1st - April 30th
Register by March 15th
This promotion is different for everyone. It depends on status I think. I wasn't status last year when they did this twice and was offered 2 stays are 1 free 1-4 cat reward. I'm status now and still got this.
  • There are 4 of them out there targeting different people. You have to log in to see which you qualify for
    • For every 2 stays, get a free night certificate at a Category 1-4 hotel (Max of 3 free nights [6 stays])
    • For every 2 stays, get a free night certificate at a Category 1-5 hotel (Max of 2 free nights [4 stays])
    • Stay 15 nights get 25,000 points or stay 20 nights get 40,000 points
    • Stay 20 nights get 35,000 points or stay 25 nights get 50,000 points
This promotion is always good. I like it a lot but the max cap limits my staying at Marriotts this quarter. The other people I work with always stay at Marriotts and they usually get the 25 nights for 50,000. This is how they lock in Marriott loyalists for the quarter.

Note: If you don't stay at Marriotts, to max this quarter out, hop hotels every night. If you stay 3 nights in a given week, after 2 weeks you can have 3 free nights and the points that go with the stays. Pretty damn good.

Starwood Q1 2013 promotion - SPG Power Up promotion
Valid January 15th - April 15, 2013
Earn up to 18,000 bonus Starpoints.
  • 2,000 bonus Starpoints for every 4 eligible nights you stay (MAX 8,000 bonus and 16 nights)
  • 10,000 bonus Starpoints when you hit 20 eligible night
This promotion is ok. The points go much further than Hilton or Marriotts so don't look at this 1:1 with the others. It's not a game changer for me so I might pass on this one.
 

Ad hoc reporting and AX 2012 vs AX 2009

In AX 2009, there were three ways that end users could do ad hoc reporting outside of Excel:
  • Report Wizard (Microsoft Dynamics AX -> Tools -> Development Tools -> Wizards -> Report Wizard
    • Creates a MorphX report in the layer that the end user is in  (USR)
    • How to create them: I WILL WRITE A POST ABOUT THIS
    • This is a great tool that even allows for the creation of labels and menu items
    • Can be problematic
  • Report Builder (Microsoft Dynamics AX -> Tools -> Business Intelligence (BI) tools -> Report Builder
  • Auto-reports
    • This is not truely an end user thing as you need to do it in the AOT.
    • It will produce a report showing the fields from the AX table that are in the AutoReport Field Group.
    • To get to this, you right click on the AX table, go to Add-Ins, then go to 'Auto-report'.

From what I've seen in AX 2012, the only self-service BI tool that still exists is the Auto-reports.  It is now accessible out side of the AOT, too. The first two reporting types discussed at the top are the most helpful but are no longer available.  Partially because MorphX reports are supported but no longer shipped with the AX product.

To use AX 2012 Autoreport functionality, you need to go to File -> Print -> Print and you will now hit the autoreport functionality.  I'm not a huge fan of that since its not very intuitive in my opinion.

The big push since Excel integration was introduced has been around PowerPivot (http://www.microsoft.com/bi/en-us/solutions/pages/powerpivot.aspx)  and utilizing Excel 2010 to get that self-service BI.  I personally like this approach since even kids know how to use Excel.  There is a reason people joke that it is the 'largest ERP in the world'.

My suggestion to people who do reporting for AX as a customer, vendor, end user, etc is that you get smart on Excel again if you are somewhat hazy with it.  Microsoft has continually updated the functionality and it is an incredibly powerful product. That Excel 101 class in 4th grade or Sophmore year in college won't be enough due to the complexity of the new features and the amount of brain cells that were killed during those classes from eating glue or drinking beer (not respectively speaking).

Tuesday, December 25, 2012

Southwest Companion Pass Direct Link

I was attempting to book a companion pass via Southwest and for some reason, the option to add a companion sometimes doesn't show up with my reservation for quite some time. Not sure why this is the case but I always want to book the companion right after I book my ticket so it doesn't fill up or I forget.

I found this trolling around on the net and confirmed it works perfectly! You can copy and paste the below URL in your web browser and replace the bolded confirmation number below with your confirmation number from the account with companion pass and it goes straight there. No need to wait! I use it now over any other option.

http://www.southwest.com/account/rapidrewards/bookCompanion.html?recordLocator=XCDJGH&ss=0
 
If you're unfamiliar with Southwest's companion pass, its the best frequent flier benefit in the skies today. You can book a flight with dollars OR points and one designated person (can only change 3 times in a year) can fly with you for $2.50 each segment (TSA fee). It's basically buy one get one free. There is no restriction on how many times you can do this in a year. It won't work for flights though AirTran. Simply fly 100 qualifying one-way flights or earn 110,000 Qualifying Points in one calendar year.

Monday, December 24, 2012

Table Ids - out of sync remedies/prevention


Note that the below was written in 2010 with AX 4.0 and 2009 in mind.

Sometimes table Id's will become out of sync between environments. The number one way that this is found out is when someone promotes tables that were created after other tables that are unpromoted to a new environment without the 'Import with ID values' checked and then other tables promoted with that check box checked on the import. Remember that AX manages and drives what is in SQL including indexes, fields, relations, etc.





About table Ids:
SQL uses Table Ids to uniquely identify tables in SQL. AX determines, stores, and manages table Ids, not SQL. For this reason, if table Ids need to be changed, they should be changed through AX. When a SQL refresh


Why it is important to have the table Id's in sync between environments?
Simple answer: SQL refreshes to lower environments are only possible when Id's are in sync. If they are out of sync, there are all sorts of issues that can pop up including data loss. Honestly, there is no reason that ID's should be out of sync as long as everything is managed properly. Be diligent or you're going to have a bad time.
 

When would you import code without table Id's checked?
If there are multiple development environments where developers are working and will ultimately be moving all code to one environment (e.g. 4 dev environments, 1 test), the id's from the test environment will be where the id's will be created.
 

How are Id's created in AX?
AX 2012 Ids will not be the same formula as below. AXUtil assigns base Ids at install and new ones regardless of layer increment off of a 6 digit number (eg 105067)
When tables, fields, classes, etc are saved in the AOT, they grab the next available Id based on the layer they are imported into. Each layer has 10000 ids that it can use. The below shows the values of the Ids that would be created based on the layer.
  • BUS – 2xxxx (e.g. 20014)
  • VAR – 3xxxx (e.g. 30014)
  • CUS – 4xxxx (e.g. 40014)
  • USR – 5xxxx (e.g. 50015)
How to correct the scenario where table Id's are out of sync.

There are multiple ways to take care of syncing environments but some methods may be better than others depending on the situation. If different data is needed to be retained in different environments, option 1 below cannot be taken as it would wipe out the data in the non-master environment when the tables are synchronized
  • Syncing all environments based on a single, 'master' environment (more than likely PROD)
    • Put a code freeze on all environments
    • Export any code that is not in the 'master' environment
    • Refresh environments' app folders with the 'master' environment's app folder
    • Reimport unpromoted work back into the appropriate environments making sure that table Id's will not overlap between environments
  • Manually change Table Id's in Notepad from XPO
    • Try exporting the object (with id's), then edit the xpo in notepad to change the id, then reimport the object (with id's) from the edited xpo.
    • Export the tables of interest (specific ones or an entire layer)
    • Import the modified XPO with ID values
  • Manually change Table Id's in AX via X++
    • This can be tricky if you are trying to change an id to a value that is already set to another table. This approach could cause data loss in sync if not careful.
    • Use the following methods to do change the table ids. They're pretty self explanatory
      • The most useful ones
        • ReleaseUpdateDB::changeTableId(_oldTableId, _newTableId, _tableName);
          • Changes the table Id from one value to another
        • ReleaseUpdateDB::changeFieldId(_tableId, _oldFieldId, _newFieldId, _tableName, _fieldName); 
          • Changes the field Id from one value to another.  
      • Other options 
        • ReleaseUpdateDB::changeTableByName(_sqlName, _oldTableId, _newTableId);
        • ReleaseUpdateDB::changeFieldByName(_sqlNameOld, _oldTableId, _newTableId, _fieldIdNew);
        • ReleaseUpdateDB::changeTableByAOTName(_nameAOT, _oldTableId, _newTableId);
        • ReleaseUpdateDB::changeFieldByAOTName(_nameAOT, _oldTableId, _newTableId, _newFieldId)
    • I have some code to do this but you can check sample code here for some ideas. I thought it was pretty solid: http://dev.goshoom.net/en/2011/11/id-change/  Thanks to
       


SysDictTable dictTable;
DictField dictField;
TableId tableId;
FieldId fieldId;
SqlDictionary sqlDictionaryTable;
SqlDictionary sqlDictionaryField;
 
setPrefix("Update of data dictionary IDs");
tableId = dictionary.tableNext(0);
ttsbegin;
 
while (tableId)
{
    dictTable = new SysDictTable(tableId);
    setPrefix(dictTable.name());
 
    if (!dictTable.isSystemTable())
    {
        //Finds table in SqlDictionary by name in AOT, if ID was changed.
        //Empty field ID represents a table.
        select sqlDictionaryTable
            where sqlDictionaryTable.name == dictTable.name()
            && sqlDictionaryTable.fieldId == 0
            && sqlDictionaryTable.tabId != dictTable.id();
 
        if (sqlDictionaryTable)
        {
            //Updates table ID in SqlDictionary
            if (ReleaseUpdateDB::changeTableId(
                sqlDictionaryTable.tabId,
                dictTable.id(),
                dictTable.name()))
            {
                info(strFmt("Table ID changed (%1 -> %2)", sqlDictionaryTable.tabId, dictTable.id()));
            }
        }
 
        fieldId = dictTable.fieldNext(0);
 
        //For all fields in table
        while (fieldId)
        {
            dictField = dictTable.fieldObject(fieldId);
 
            if (dictField.isSql() && !dictField.isSystem())
            {
                //Finds fields in SqlDictionary by name and compares IDs
                select sqlDictionaryField
                    where sqlDictionaryField.tabId == dictTable.id()
                    && sqlDictionaryField.name == dictField.name()
                    && sqlDictionaryField.fieldId != 0
                    && sqlDictionaryField.fieldId != dictField.id();
 
                if (sqlDictionaryField)
                {
                    //Updates field ID in SqlDictionary
                    if (ReleaseUpdateDB::changeFieldId(
                        dictTable.id(),
                        sqlDictionaryField.fieldId,
                        dictField.id(),
                        dictTable.name(),
                        dictField.name()))
                    {
                        info(strFmt("Field %1 - ID changed (%2 -> %3)",
                            dictField.name(),
                            sqlDictionaryField.fieldId,
                            dictField.id()));
                    }
                }
            }
            fieldId = dictTable.fieldNext(fieldId);
        }
    }
    tableId = dictionary.tableNext(tableId);
}
ttscommit;

Thursday, December 20, 2012

Compare versions of Windows 8 features

The below is a little information about the different versions of Windows 8. Microsoft did a little rebranding of the versions from Vista and 7. They attempted to make it easier to understand the versions from the names alone instead of 'Starter', 'Home Basic', 'Home Premium', 'Ultimate', etc.

If you already have Windows 8 installed you can find out your version by going to the control panel, then selecting 'System and Security' then 'System'. The screen and version is in Figure 1.

You can navigate to the control panel 3 ways:
  1. In the Windows 8 start screen, start typing 'Control Panel' then you will see the icon
  2. In Desktop mode (click the desktop icon in W8 view), move your cursor to the bottom left corner, then right click. You will see a Control Panel option to click
  3. Right click inside W8 start screen, select 'All Apps'. The Control Panel option will be available there
Figure 1 - The Windows version that is being run

Windows 8 
Windows 8 is the basic edition of Windows for the IA-32 and x64 architectures. Some people refer to this edition as 'Core' Windows. This edition contains features aimed at the home market segment and provides all of the basic new Windows 8 features.

Windows 8 Pro (or Windows 8 Pro with Media Center)
Windows 8 Pro is comparable to Windows 7 Professional and Ultimate and is targeted towards enthusiasts and business users; it includes all the features of Windows 8. Additional features include the ability to receive Remote Desktop connections, the ability to participate in a Windows Server domain, Encrypting File System, Hyper-V, and Virtual Hard Disk Booting, Group Policy as well as BitLocker and BitLocker To Go. Windows Media Center functionality will be available only for Windows 8 Pro as a separate software package.

Windows 8 Enterprise 
Windows 8 Enterprise provides all the features in Windows 8 Pro (except the ability to install the Windows Media Center add-on), with additional features to assist with IT organization (see table below). This edition is available to Software Assurance customers, as well as MSDN and Technet Professional subscribers, and was released on August 16, 2012.

Windows RT
Windows RT will only be available pre-installed on ARM-based devices such as tablet PCs. It will include touch-optimized desktop versions of the basic set of Office 2013 applications to users—Microsoft Word, Excel, PowerPoint, and OneNote, and support device encryption capabilities. Several business-focused features such as Group Policy and domain support are not included.
 http://en.wikipedia.org/wiki/Windows_8_editions#cite_note-official1-4

Comparison of Windows 8 editions
Features Windows RT Windows 8 Windows 8 Pro Windows 8 Enterprise
Availability Pre-installed on devices Most channels Most channels Volume License customers
Architecture ARM (32-bit) IA-32 (32-bit) or x64 (64-bit) IA-32 (32-bit) or x64 (64-bit) IA-32 (32-bit) or x64 (64-bit)
Maximum physical memory (RAM) ? 4 GB on IA-32
128 GB on x64
4 GB on IA-32
512 GB on x64
4 GB on IA-32
512 GB on x64
Trusted boot Yes Yes Yes Yes
Picture password Yes Yes Yes Yes
Start screen, Semantic Zoom, Live Tiles Yes Yes Yes Yes
Touch and Thumb keyboard Yes Yes Yes Yes
Language packs Yes Yes Yes Yes
Updated File Explorer Yes Yes Yes Yes
Standard apps Yes Yes Yes Yes
File History Yes Yes Yes Yes
Refresh and reset of OS Yes Yes Yes Yes
Play To Yes Yes Yes Yes
Connected standby Yes Yes Yes Yes
Windows Update Yes Yes Yes Yes
Windows Defender Yes Yes Yes Yes
Better multi-monitor support Yes Yes Yes Yes
New Windows Task Manager Yes Yes Yes Yes
ISO image and VHD mounting Yes Yes Yes Yes
Mobile broadband features Yes Yes Yes Yes
Microsoft account integration Yes Yes Yes Yes
Internet Explorer 10 Yes Yes Yes Yes
SmartScreen Yes Yes Yes Yes
Windows Store Yes Yes Yes Yes
Xbox Live app (including Xbox Live Arcade) Yes Yes Yes Yes
Exchange ActiveSync Yes Yes Yes Yes
Snap Yes Yes Yes Yes
Can connect to a VPN? Yes Yes Yes Yes
Desktop Partial Yes Yes Yes
Supported third-party apps Windows Store apps only Windows Store and desktop Windows Store and desktop Windows Store and desktop
Remote Desktop Client only Client only Client and host Client and host
Storage Spaces No Yes Yes Yes
Windows Media Player No Yes Yes Yes
Encryption features Device encryption[b] Unavailable BitLocker and EFS BitLocker and EFS
Sideload Windows Store apps Partial[c] No Partial[c] Partial[c]
Boot from VHD No No Yes Yes
Can join a Windows domain? No No Yes Yes
Group Policy No No Yes Yes
Hyper-V No No On 64-bit versions only with SLAT capable CPU
AppLocker No No No Yes
Windows To Go No No No Yes
DirectAccess No No No Yes
BranchCache No No No Yes
Can be virtualized by RemoteFX? No No No Yes
Services for Network File System No No No Yes
Microsoft Office apps bundled with OS Yes No No No
Windows Media Center No No Via an add-in[25] No
Feature Windows RT Windows 8 Windows 8 Pro Windows 8 Enterprise
 http://blogs.windows.com/windows/b/bloggingwindows/archive/2012/04/16/announcing-the-windows-8-editions.aspx 

Wednesday, December 19, 2012

Windows 8 Member of Domain greyed out and unselectable

UPDATE: This is also the case with Windows 10. You'll have to upgrade from Windows 10 Home to Window 10 pro to join the domain. Its only about $99 (as of 1/11/2017) and can be completed on the actual POS device.

I recently installed Windows 8 on my PC and was attempting to join it to our corporate domain but was unable. The 'Domain' button and field in the 'Member of' group were greyed out and unselectable (Figure 1 below).
  1. As a first step, make sure the that Workstation is running (Figure 2 below). If its running, restart it and confirm the domain is still not working
  2. Check the version of Windows 8 (Figure 3 below)
    1. If it just says Windows 8 (like highlighted in Figure 3), thats the issue. Windows 8 'Home' edition can't join networks.
For me, step 2 above was the issue. I needed to upgrade to Windows 8 Pro or Enterprise. This can be easily done through the system by clicking on 'Get more features with a new edition of Windows' as seen in Figure 3 in the 'Windows edition' group. This will prompt you with Figure 4 where you can either enter a Windows 8 Pro key (if you already have one) or you can buy it through the system.

If you buy your key through that tool, the system will automatically install new features and restart a few times.

NOTE: Make sure that you have a Windows 8 bootable media device before going any further. I encountered a variety of issues in the earlier versions of this product causing errors that prevented boot up of the OS without the ability to access the advanced boot options.

<!--7/17/2015 NOTE: This post was from 2012. The below isn't really valid anymore but retaining it for historical purposes-->
If you buy your key, you can enter a promo code to get the upgrade price of $40 or less instead of $70. Even though I had a valid Windows 7 key, I could not enter a promo code (the original Windows 7 key) nor could I use a code from http://windowsupgradeoffer.com/ to lower the price. Neither codes worked for me so I paid full price. Full price is still an amazing deal for something you use every day. It's a solid piece of software.

You can actually buy Windows 8 Pro for $15 through windowsupgradeoffer.com without buying a new PC. I don't recommend it as its unethical but you can just fill out the personal information and pick out a PC Brand (Dell), name of retailer (Best Buy), and PC model (Latitude). Just make sure the Date of Purchase is within the required time frame for the offer. You'll get a promo code in your email within 4 hours and you can use that.

 Figure 1 - The Member of Domain button and field are disabled



Figure 2 - Make sure the Workstation service is running. Restart it to be safe

Figure 3 - Navigate to the above and check the version of Windows.




 Figure 4 - The 'Add features to Windows 8' screen

Thursday, December 13, 2012

Windows 8 Cisco VPN error - Reason 442: Failed to enable Virtual Adapter

I did a clean install of Windows 8 on my laptop and was reinstalling software. I was importing and attempting to connect to a client that used a Cisco setup but was hitting the error: "Reason 442: Failed to enable Virtual Adapter." seen in Figure 1.

SOLUTION: Needed a registry change for Cisco because of an issue with the program on Windows 8. Solution at below in post:



Figure 1 - Reason 442 error

Things went down in the following fashion:
  • I wasn't already on the network via hard wire. Of course not
  • The VPN Network adapter was enabled. Didn't work
  • Make sure the VPN client was on the latest and greatest release. Sure is
  • Clicked on diagnostic for troubleshooting. Got the information in Figure 2
  • Ran 'ipconfig \release' and 'ipconfig \renew' in command prompt. Nothing...
  • Made changes to the registry per the below post. WORKED!
Here are the steps to making the registry change to fix this Reason 442 error.
  1. Navigate to the registry
    1.  Hit Windows Key+R (This opens the Run prompt)
    2. Type 'regedit' in the field and click 'OK' (or just hit the enter key
  2. Navigate to HKEY_LOCAL_MACHINE\SYSTEM\CURRENTCONTROLSET\SERVICES\CVIRTA
  3. Locate the DisplayName key (Figure 3 below)
  4. Change the value to the following
    1. x86 (32-bit) - "@oem8.inf,%CVirtA_Desc%;Cisco Systems VPN Adapter” to "Cisco Systems VPN Adapter”
    2. x64 (64-bit) - "@oem8.inf,%CVirtA_Desc%;Cisco Systems VPN Adapter for 64-bit Windows” to "Cisco Systems VPN Adapter for 64-bit Windows”
If that doesn't work, you can change the settings back but it won't do anything for you.

Its that simple!

Figure 2 - Troubleshooting diagnostic results. It's a red herring..


Figure 3 - Registry key location for the DisplayName key

Figure 4 - Change the key name to 'Cisco Systems VPN Adapter for 64-bit Windows'

Friday, December 7, 2012

How to install a new font on Windows 7

I was trying to install a windows 7 font and couldn't figure it out. I had some old tutorials from Windows Vista and even Windows 3.1 but the install for Windows 7 didn't seem to mesh with what I was reading on blogs.

One gripe I have with things on the internet is that some people make things seem so complicated. This is really a one picture step, not 14 (at least in this example). All you have to do is right click on the font and select 'install'. There will not be a prompt that shows up after doing so.

Note that if you have a program like Photoshop, GIMP, or something running during the install, you will probably need to restart those programs to see the new font.

Thats it! If you hit issues with this or its more complex, I haven't run into it but post it below and we can figure it out. No problems there.

Thursday, December 6, 2012

Unable to install Visual Studio 2012 in Windows 8

I was trying to install Visual Studio Premium 2012 (VS 2012) in Windows 8 and was getting the error: ' Setup Blocked: Correct the following problems and then run setup again. Click here to see the most common issues and workarounds or here to review the log file.  [XMARK] The computer needs to be restarted before setup can continue. Please restart the computer and run setup again.'

I looked at the log file and saw the following as the last 5 lines:
[0D3C:0698][2012-12-06T11:28:31]: MUX:  Non-applicable packages grouped by Selectable Items:
[0D3C:0698][2012-12-06T11:28:32]: MUX:  User feedback control is Enable because opt-in value is NotDefined
[0D3C:0D34][2012-12-06T11:28:32]: MUX:  View loaded
[0D3C:0D34][2012-12-06T11:28:32]: MUX:  Go to Blocker page.
[0D3C:0D34][2012-12-06T11:28:32]: Detect complete, result: 0x0


I was able to resolve this issue by installing the latests Windows updates and restart the machine. Pretty simple. Go figure that the infolog would actually tell me correctly what to do without the help of the label file.

Tuesday, November 13, 2012

AX show container in infolog

There are times where you want to show a container in a window. For example, if you are implementing AX 2012 for Retail, you can send containers back to the POS.

For example, you may want to run a job in AX that mimics the retail transaction services (RTS) call that the POS is calling and see the raw data in AX thus totally eliminating the need for the POS in the testing process. I used this scenario in the below code using a dummy RTS method.

    Object      FormRun = classFactory.formRunClass(new Args(FormStr(SysConView)));
    FormDesign  design;
    Container   c; // The container we want to view

    formRun.init();

    if (!prmIsDefault('Caption'))
    {
        design = formRun.design();
        design.caption('Caption');
    }

    // Use an RTS call and build/return a container using a customer id
    c = RetailTransactionService::containerExample('ARCA-000007');

    formRun.setContainer(c);
    formRun.run();
    formRun.detach();     

The result from this code will look like:

Thursday, November 8, 2012

Formatting code into blogs

When pasting code into a blog post, there are a few ways that the information can be displayed. I've really done a consistent job of making the code readable.  This post will detail out two different ways that this can be reliably done. In order to format code, you will need to switch to the HTML editor portion of the blog as the other visual editing mode won't allow this.

CODE STYLE 1: 
Doing this style is preferable in my opinion as it looks clean and allows the user to scroll over to the code in case there are long lines that would normally bleed off the page or do a word wrap.

Syntax:
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code> INSERT CODE HERE </code></pre>

The code above would look like the below:
 INSERT CODE HERE 

Here is an example of it in action:

CODE STYLE 2:
The below is useful if you want to use CSS for formatting code across multiple posts. The class attribute (using 'code' name) is mostly used to point to a class in a style sheet. However, it can also be used by a JavaScript (via the HTML DOM) to make changes to HTML elements with a specified class.

Syntax:
<pre class="code"><span style="font-size: x-small;">INSERT CODE HERE </span></pre>

The code above would look like the below:
INSERT CODE HERE 


Here is an example of it in action:

Tuesday, November 6, 2012

AX 2012 Find On Hand (Physical) Inventory By Date

Below is a quick way to return the On Hand (Physical) Inventory for an item and dimension value combination (variant and location in AX Retail term). Note that this is for on hand inventory, not ATP or anything. This method assumes that you are passing an item, an inventory dimension record, and a date.

Parameters:
  • _itemId - The Item Id for the item
  • _inventDim - The inventory dimension record for the item (variant)
  • _date - The date that we want to see the on hand inventory amount for

private Qty findOnHandByDate(ItemId _itemId, InventDim _inventDim, Date _date)
{
    InventDimParm    inventDimParmCrit;
    InventSumDateDim inventSumDateDim;
    ;

    // Set the dimensions
    inventDimParmCrit.initFromInventDim(_inventDim);
    inventSumDateDim = inventSumDateDim::newParameters(_date, _itemId, _inventDim, inventDimParmCrit);

    return InventSumDateDim.postedQty();
}

Monday, October 29, 2012

Check if XML node exists in AX

Depending on where the XML is coming from, an XML node without a value may not come through as </Node> or <Node></Node> where 'Node' is the attribute/element of interest in this example. It may be completely left out depending on how things were coded.

In AX, if a node does not exist in the XML document and we try to read a value from a node that doesn't exist, a stack trace error is thrown. This is obviously not good.  We may need to 1) verify the node exists in the XML and then 2) extract the value.

For scenarios where this occurs, to prevent a stack trace error, you can do the below in the example where we may not have a 'RecId' node in the incoming XML.



XmlDocument   itemAndDateXml;
XmlElement    xmlRoot;   
XmlNodeList   xmlRecordList;
XmlElement    xmlItemRecord;
int           itemCounter;


itemAndDateXml = new XmlDocument();
itemAndDateXml.loadXml(_xml); // this is the xml string
xmlRoot = itemAndDateXml.documentElement().getNamedElement('Items');
xmlRecordList = xmlRoot.childNodes();

for (itemCounter = 0; itemCounter < xmlRecordList.length(); itemCounter++)
{
    xmlItemRecord = xmlRecordList.item(itemCounter-1);

    id      = xmlItemRecord.getNamedElement('Id').text();
    variant = xmlItemRecord.getNamedElement('Variant').text();
    qty     = str2Int(xmlItemRecord.getNamedElement('Qty').text());
   
    // Make sure that the node exists or the system will throw a stack trace error
    if (xmlItemRecord.selectSingleNode('RecId'))
        recId = str2recId(xmlItemRecord.getNamedElement('RecId').text());
}

Tuesday, October 2, 2012

Automatically format an XML string

Sometimes you get an XML string and it is unformatted. And doesn't have any tabbing and is hard to read. You can copy and paste this string into a box in the link below and it will do that formatting for you.

Fun tool that I use a lot of:  http://www.freeformatter.com/xml-formatter.html

This is the XML string unformatted
<XML><Items><Item><Id>60000</Id><Varient>CEU-000001</Varient></Item> </Items></XML>'
 
This is the XML string after the formatting
<?xml version="1.0" encoding="UTF-8"?>
<XML>
   <Items>
      <Item>
         <Id>60000</Id>
         <Varient>CEU-000001</Varient>
      </Item>
   </Items>
</XML>

 
It is a really slick tool that is free to use. I know its saved me a ton of time.

Tuesday, September 25, 2012

Simple AX container example

Below is a simple example of creating and inserting values into a container, determining the size of the container, and looping over that container to retrieve the values from it.

Since this is a job and I wanted to test out embedding methods into the job, I included that little complexity in here. All that it does is either fill the container with data or leave it empty based on the 'dataInCont' value which stands for data in container. Note that this variable is a global so when declared in that location and using embedded functions/methods, this location acts as the class declaration.

This is AX development 101 stuff but I was using it in a training sample so I decided I might as well slap the code on my blog as well as the resulting information log.

Enjoy!


static void daxTestJob(Args _args)
{
    container cont;
    int i;
    boolean dataInCont = true; // Do we want to run this job with container data? Note this is a global
   
    // This method will either return an empty container or one with data
    container test()
    {
        container contTest;
       
        if (dataInCont)
        {
            contTest += 5;
            contTest += 6;
            contTest += -52;
            contTest += 'DAXDUDE';           
        }
       
        return contTest;
    }
    ;
          
    cont = test();
   
    info (strFmt("Length of the container: %1", conLen(cont)));
   
    for (i=1; i <= conLen(cont); i++)
    {
        info (strFmt("container value %1 is %2", i, conPeek(cont, i)));  
    } 
}

Resulting infolog from code above:

Friday, September 21, 2012

AX 2012 Issue - New field to table and field group saying 'Unretrievable' and disabled

I encountered an issue when adding a new field to an AX table and putting it in a field group. When a form is opened that has a section for this field group where the new field was added has the field disabled and there is text in the field entry section that reads 'Unretrievable' in AX 2012.
QUICK SOLUTION: Weird table sync issue.

Field added to base AX table and field group disabled and reading 'Unretrievable'

I have never seen this happen before in any other AX 2012 environment and was occurring in a development environment where TFS was enabled. It's a pretty simple scenario so I'm not sure why I was seeing what I was seeing. It doesn't get much easier than this. The table was recompiled and synced, environment open and closed,  I actually even tried this in several other environments and was not able to replicate this issue. It was just in the TFS synced environment. I could write data in the table browser back-end but not via the form.

SOLUTION: Looks like this was an issue with the syncing of the EDT/Table. I was able to fix this by creating a new field and trying again. I eventually was able to get one to stick. Not sure what was going on. Looks like an issue with the synchronization.

After I had everything working, I changed the alignment property on the data type, synced the EDT, and this issue came back. I then changed the property back, synced the EDT again and the the issue was fixed. I then switched the alignment back to what I wanted, synced, and the issue was fixed then.


Thursday, September 20, 2012

Max AX method name and best practices

The maximum length for an AX method in AX is 40 characters.

If the name is too long you'll get the compilation error 'Name is too long. Truncate name to '[>40 character method name here]'.

Remember when you name your AX classes, the names should start with the three letter prefix [e.g. abc], then the module it belongs to [e.g. Sales], then the functionality that it follows where appropriately, ending with a brief description of the purpose. The ultimate goal is to be able to see the class name and know exactly what the class extends and if its custom and what it does.

The methods within this class then should be able to not only follow the base overrides (find, exist, modifiedField, etc), but also provide a directed purpose where appropriate. It is good to keep in mind the best practices behind a method when determining the name of the methods.

A refresher around the functions of AX methods best practices. There are a lot more than the below (like keeping variables as local as possible) but these are general.

MSDN: Best Practices for Methods [AX 2012]
Methods should:
  • Be logical.
  • Do a specific task.
  • Have no side effects.
  • Be well structured, especially when it comes to good places for overriding and for overlayering.
Make your methods small and logical. If you have a method that does more than one 'thing'; then consider splitting it up in two (or more) methods. It will then be easier to override or overlayer exactly the functionality that needs to be specialized or customized.
Do not have any unused variables in your methods.

Wednesday, September 19, 2012

Select statement where condition formatting and placement in Dynamics AX

In Dynamics AX X++, there are a few ways to format a select statement and place the where clauses when using multiple joins. See the two examples below. Both do exactly the same thing but note the difference in placement of the where conditions. Just making sure people know this. Apparently some people do not so at least now its out on the internet somewhere.

I don't believe there is a best practice around this but it should be consistent in your development either way. I prefer option 1 as it reads better in my opinion. The where conditions can be separated a little more and linked back to their initial data source.


OPTION 1:
public static Name storeOperatingUnitName(RecID _storeRecId)
{

    RetailChannelTable      retailChannelTable;
    DirPartyTable           dirPartyTable;
    OMOperatingUnit         operatingUnit;
    ;

    select firstOnly recId from retailChannelTable
        where retailChannelTable.RecId == _storeRecId
        join recId from operatingUnit
            where operatingUnit.RecId               == retailChannelTable.OMOperatingUnitID
               && operatingUnit.OMOperatingUnitType == OMOperatingUnitType::RetailChannel
            join name from dirPartyTable
                where dirPartyTable.RecId == operatingUnit.RecId;                  

    return dirPartyTable.Name;
}


 OPTION 2:
public static Name storeOperatingUnitName(RecID _storeRecId)
{

    RetailChannelTable      retailChannelTable;
    DirPartyTable           dirPartyTable;
    OMOperatingUnit         operatingUnit;
    ;      
   
    select firstOnly RecId from retailChannelTable       
        join RecId from operatingUnit           
            join Name from dirPartyTable
                where retailChannelTable.RecId           == _storeRecId
                    && operatingUnit.RecId               == retailChannelTable.OMOperatingUnitID
                    && operatingUnit.OMOperatingUnitType == OMOperatingUnitType::RetailChannel
                    && dirPartyTable.RecId               == operatingUnit.RecId;

    return dirPartyTable.Name;
}