Wednesday, January 23, 2008

Microsoft FY08Q2 Results

FY08Q2: As always, my favorite post-analysis sites for the results:

At a simple level, I feel anything that Microsoft reports is like spitting in the wind during the current financial storm. I'll be interested in hearing if we have anything encouraging to say as being a safe-haven for investors during this period, given the current releases and the upcoming releases.

Mr. Todd Bishop has a preview and nails my concern about the analysts concern of our forward looking statements. Also - though I doubt it will come up except as a generalized catch-all warning - with the EU feeling us up again to try to figure where we moved our wallet to, we have more legal uncertainty to deal with.

Update: After the release...

FY08Q1: ba-da-Boom!

FY08Q2: ba-da-BING! (or should that be, "ba-da-Cha-CHING!"?)

Channeling an upbeat attitude that could be heard as, "no, really, our poo doesn't stink," Mr. Liddell got to take lead on one of the most positive and reassuring Microsoft quarterly results conference calls I've heard in a long time. He expressed extreme pleasure over the results, as do I imagine every Microsoftie (unless you do want to point at the stinky poo of OSB and how E&D / Xbox has a deep, deep hole of billions to fill income into).

I'd say every time I heard an analyst try to give Mr. Liddell a soft-pitch opportunity to say something negative or overly cautious, Mr. Liddell was like, "Nope, things are going great, and will continue going great. Or greater."

Safe-haven for the investors' money, indeed!

Oh, and kudos to Jason Maynard for asking Liddell about the new EU actions and how that figured into Liddell's thinking. Not much of a meaty answer (well, most of the answers weren't very meaty) but it was nice to hear such a challenging question. I hope it comes up again during our Friday Town Hall Meeting in 34, though I wouldn't expect a more detailed answer.

Follow-up posts:

MSFTExtremeMakeover: Q2 FY08 Earnings. Snippet:

Short version: strong results, increased guidance, generally upbeat tone, and no really embarrassing items for analysts to question. Good job! Yes, online continues to be a sinkhole for cash. But everyone is used to that by now, and at least the top line result is semi-respectable. Yes, there's still no color on actual large scale Vista deployments. But at least client revenue and unearned remains solid. Bottom line, if last report was sufficient to get some investors to take another look at MSFT, then this one should attract others and perhaps reduce doubts that last time was merely a fluke.

Mr. Joe Wilcox: Microsoft Watch - Corporate - Microsoft Q2 2008 by the Numbers. Snippet:

Liddell's confidence may have something to do with where Microsoft makes its money. Just four years ago, the majority of revenue came from North America. Now, 60 percent of sales are outside the United States, Liddell said. For the quarter, Microsoft sales increased 30 percent in emerging markets, 20 percent in established markets like Europe and 15 percent in the United States.

Even if the U.S. economy slows down, overseas sales could offset any decreases in technology spending here.

Mr. Todd Bishop: Microsoft beats quarterly estimates, raises forecast. Snippet:

Microsoft's Online Services Business was the only one of the company's five divisions to post an operating loss for the quarter, $245 million in the red. The company's Entertainment and Devices Division climbed to a $357 million operating profit thanks to holiday video-game sales. Chris Liddell, the company's chief financial officer, said this afternoon that Microsoft is still expecting that division to be profitable for the full fiscal year, which ends in June.

And the general attitude of the rest of the reports:


Now, let's be sure we don't start slipping back to our old sloppy ways, because, well, our poo does stink. Just like everyone else's.

Thursday, January 17, 2008

Creating and Posting Inventory ProfitLoss journals in DAX using .NET Business Connector

Yesterday, I was helping a friend from Canada create a small solution that would create and post ProfitLoss journals in Microsoft Dynamics AX 4.0 using .NET Business Connector.

In the end, we created 2 solutions - one was entirely written in X++, and only simple class static method calls were made from C#. The other was completely written in C#, using various classes, available with .NET business connector.

I uploaded the solution to the following link, in case anyone would be interested to download it and play around with it or use in their projects.
Download ProfitLossPostingAppl

Also, here is the source code - it is a small console application, and I tried to add as many comments as possible, so that even complete X++ beginners would be able to easily read the code.

Notice that in the solution, there is a reference to the business connector dll.
You can find the Microsoft.Dynamics.BusinessConnectorNet.dll in the Client\Bin folder of your Dynamics AX installation. This dll is what provides you with access to the Dynamics AX application and the set of classes to use AX tables and classes.

using System;
using Microsoft.Dynamics.BusinessConnectorNet;

namespace ProfitLossPostingAppl
class AxProfitLossPostingEngine
static void Main(string[] args)
Axapta ax = new Axapta();
// company name, language, object server, configuration
// this uses Windows Authentication
ax.Logon("cmul", null, "localhost", null);

// Start a transaction

// AxaptaRecord is a class that allows to work with Tables in AX
AxaptaRecord header = ax.CreateAxaptaRecord("InventJournalTable");
AxaptaRecord journalName = ax.CreateAxaptaRecord("InventJournalName");
AxaptaRecord line = ax.CreateAxaptaRecord("InventJournalTrans");
AxaptaRecord inventTable = ax.CreateAxaptaRecord("InventTable");
AxaptaRecord warehouse = ax.CreateAxaptaRecord("InventDim");

// You can call static table methods using the following syntax
journalName = ax.CallStaticRecordMethod("InventJournalName", "find", "IPL") as AxaptaRecord;

// There is a set of predefined methods on the AxaptaRecord class, like the clear(), initValue, DML operations, etc.
// You can call table object methods as well, not only static
header.Call("initFromInventJournalName", journalName);

line.Call("initFromInventJournalTable", header);
// You cannot use table fields directly as in X++. Instead you have set/get methods
line.set_Field("itemId", "B-R14");

// Instead of using static table methods (like find) you can execute a direct SQL statement and receive the result in the AxaptaRecord object
inventTable.ExecuteStmt("select * from %1 where %1.ItemId == 'B-R14'");
// If you receive more that one record you can iterate through them using Next (as in AX)
line.Call("initFromInventTable", inventTable);

line.set_Field("Qty", 160.0);

warehouse.set_Field("InventLocationId", "MW");

warehouse = ax.CallStaticRecordMethod("InventDim", "findOrCreate", warehouse) as AxaptaRecord;

line.set_Field("InventDimId", warehouse.get_Field("inventDimId"));

// Notice AxaptaRecord is passed by reference here
ax.CallStaticRecordMethod("InventJournalTable", "initTotal", header);


// You can call static class methods the same way you call table static methods, but using a different method on Axapta class
// So in case you wrote the posting in X++, you would be able to call it, passing the JournalId as the argument
// int numOfLinesPosted = (int)ax.CallStaticClassMethod("DEV_ProfitLossEngine", "postProfitLossJournal", header.get_Field("JournalId"));

// Or, you can use the AxaptaObject class to accomplish the same from C#
// You can initialize a new class using the Axapta class method
// AxaptaObject journalCheckPost = ax.CreateAxaptaObject("InventJournalCheckPost");

// Or using a static method, if that suites your needs better
// Notice here that an object of type AxaptaRecord is passed into a method that expects InventJournalTable as the argument
AxaptaObject journalCheckPost = ax.CallStaticClassMethod("InventJournalCheckPost", "newPostJournal", header) as AxaptaObject;
// You can object methods the same way you would on a table
journalCheckPost.Call("parmShowInfoResult", false);
journalCheckPost.Call("parmThrowCheckFailed", true);
journalCheckPost.Call("parmTransferErrors", false);

int numOfLinesPosted = (int)journalCheckPost.Call("numOfPostedLines");

Console.WriteLine(String.Format("{0} line(s) have been successfully posted", numOfLinesPosted));
Console.WriteLine("JournalId is " + header.get_Field("JournalId"));
Console.WriteLine("Press any key to continue ...");

catch (Exception ex)



P.S. Of course, it would probably be a better idea to use classed InventJournalTableData, InventJournalTransData, etc.
But for the simplisity of the example, everything is done directly with tables.

Wednesday, January 16, 2008

Microsoft Dynamics AX 2009 - some of the new development features

Alexei Eremenko from Microsoft Russia has posted a number of articles about the new features that will be available in DAX 2009.
The original link, which is in Russian (but the main thing to look at is the code, which is universal):

I would like to make a brief review of the features he talked about for the English-speaking population and another feature I liked that Alexei did not mention.

Let's start with the support for union in SQL statements (but only when using Query* classes).

query = new Query();
query.queryType(QueryType::Union); // The other value of QueryType is "Join"

Another Exception type has been introduced, which now actually allows to catch the DuplicateKey exception:

Table t;

while select forupdate t
test.Field1 = ‘xyz’;
catch ( Exception::DuplicateKeyException, t )
infolog(‘Record already exists - ‘ + t.Field1 );

The bulk DML statements now allow using inner/outer joins, and you can access the result of the update_recordset operation to get the number of rows that were updated:

update_recordset batchJob setting
Status = BatchStatus::Canceled,
EndDateTime = thisDate,
Finishing = 1
where batchJob.Status == BatchStatus::Cancelling
notexists join batch
where (
(batch.Status == BatchStatus::Ready ||
batch.Status == BatchStatus::Executing ||
batch.Status == BatchStatus::Hold ||
batch.Status == BatchStatus::Cancelling)
&& batch.BatchJobId == batchJob.RecId

rowsUpdated = (batchJob.RowCount() > 0); // get the number of updated rows with rowCount()

And, the feature I enjoyed, is that we now have crossCompany support in X++. Meaning you can access data from tables from a number of companies in one query.
Here are code snippets to explain what I mean:

static void DataBaseAccess_CrossCompany(Args _args)
InventTable inventTable;
container companyContainer = ['IN1', 'QMS'];
while select crossCompany : companyContainer inventTable
where inventTable.ItemId == "B-R14"
print inventTable.ItemId, " -- ", inventTable.dataAreaId;

This code will print ItemId from 2 companies, even though InventTable has the property SaveDataPerCompany set to Yes.

The same functionality is available with the Query classes:

static void DataBaseAccess_CrossCompany_Query(Args _args)
Query query = new Query();
QueryBuildDataSource qbds = query.addDataSource(tableNum(InventTable));
QueryRun queryRun;
InventTable inventTable;
qbds.addRange(fieldNum(InventTable, ItemId)).value(queryValue("B-R14"));


queryRun = new QueryRun(query);
while (
inventTable = queryRun.get(tableNum(InventTable));
print inventTable.ItemId, " -- ", inventTable.dataAreaId;

If you don't add any specific company ranges, the data will be retrieved from all companies you have access to.

Microsoft Dynamics AX 2009 has a lot more to offer, of course. But enough for today.

Thursday, January 10, 2008

Raikes and Other Exits

Well, I should be sweating to the 80's soundtrack at the ProClub with about half of Microsoft that's trying to squeeze in there for January to burn off Christmas cookies, but here everyday that passes yet another exit hits us, and today we have a biggie...

Jaffe: Exits Microsoft dealmaker Bruce Jaffe going startup - shoot, why swing billion dollar acquisitions when you can be a billion dollar acquisition?!?!

Fitzgerald: Another of the Microsoft old guard moves on All about Microsoft

Raikes! Microsoft Announces Retirement and Transition Plan for Jeff Raikes, President of the Microsoft Business Division Company announces it has hired Stephen Elop from Juniper Networks; Raikes will continue at Microsoft through September 2008.

Wow, I'm surprised. I can understand that Mr. Raikes has had a long, long career at Microsoft, but as we wonder about the leadership in the upcoming (and no doubt somewhat dysfunctional) post-Gates era, my money was riding on Mr. Raikes to step up and perhaps be on the shortlist for running more of Microsoft. At least Jeff gets to go out on a high-note.

And of all of our leadership at Raikes level, I respect him the most. There's something more to him (there is something there there) that I admired when around him.

And Stephen "Who?" Elop? I found it ironic that while Mr. Ballmer in the announcement email was praising Mr. Raikes ability to recruit, mentor and nurture Microsoft leadership, Raikes was not being replaced by someone he groomed. I tell you, if I was a Raikes direct I would seriously be considering whether I was ready for a new challenge, at Microsoft or elsewhere.

The Market's reaction on Friday? MSFT Extreme Makeover has an interesting comment on this:

The [external] choice for replacement seems to have the right pedigree, but Raikes did a solid job with Office and was widely seen as the leading candidate for eventual Ballmer replacement as CEO. So I don't think the market is going to react positively to the news tomorrow.

Two more quick things:

CES: MSFT Extreme Makeover has a compilation of BillG and CES and a take on the $1,200,000,000USD acquisition of Fast Search.

Xbox departures: a commenter makes the following observation:

It's weird that Mini and all the commenters here have failed to notice the mass exodus from the Xbox team in 2007. By my count, more than 15% of the product team (dev/PM/test) have left Microsoft for Apple, Sony, Google, Yahoo, MySpace, Amazon, and various other companies (including several startups, local and in the Valley).

This is great progress towards a Mini-MSFT!!

(Though, it's mostly bad attrition and has some other negative implications you can work out on your own.)

The main complaint I hear about the games / Xbox area is things are drying up given the "show me the money" religion that's been adopted. Some pet projects (or just random projects) that had nothing to do with future profit have been disbanded. Man, I can't even squeeze out some crocodile tears for that...

Administrivia: expect more CRF'ing after that last post. Boy, did that suck given all the high hopes I had for positive, aspirational comments. I'm bearing a grudge. I'm human. I'm upping the moderation a bit more to be on-topic and less open to general gripes by anti-Microsofters.