(Q) Why do I get records full of NULLs when I'm using the Resource Type measure?
(A) This question is about ClickAnalyze Reporting for ClickSchedule. More specifically it is raised in regards to the Resource Schedule report.
By now, you probably noticed that engineers with assignments have one record per assignment, but engineers with no assignments have one record full of NULL values. The NULL values are at the columns, which hold the assignment and task details.
Why there is no such record for engineer with assignments? Why engineer with no assignments, don't have zero records? Meaning that this NULLs record should not be written at all!
Well, the answer is in the question: the Resource Type measure.
When the reporting infrastructure initialize the calculators (measures), each calculator declares what type of objects it needs. In the first screen-shot we can see that Resource Type asks for Engineer objects (see the Conditions and Data Filter properties).
The "Task" measure is a Get Schedule measure type. It's also requires Engineer objects, but it returns matrix of values.
Here is the place to explain what is this "matrix of values": Each calculator defines list of columns that it can populate. The Get Schedule calculator defines this list from the parameters entered by the user (Task Properties and Assignment Properties). Assuming the list is made of 5 task properties and 3 assignment properties, then the calculator defines 8 sub-columns. Each time the infrastructure is calling the calculator with Engineer objects, it prepares array with 8 NULL values, and the calculator can write values into those places. But here comes the special part, the Get Schedule calculator fills the 8 values from the first task-assignment pair, and then calls the infrastructure to AddRow. The infrastructure duplicate all values of the preceding dimensions and measures and prepare new array of NULL values, so the calculator can now start writing the second row of the matrix, and so on.
When the Get Schedule calculator have no assignments to process, it leaves the array full of NULL values and exit. If the infrastructure finds that all measures are returning only NULL values, then the record is not written to the database.
BUT, in our case, the Resource Type measure always write a string value, so we get this record full of NULL values (the NULL values, which the Get Schedule measure did not fill).
We should note that by design, the special "matrix measures" should be the only measure in the report. It is by coincidence that the infrastructure supports one "matrix measure" as the last measure, even when it is preceding with other simple measures.
I would expect this Resource Type calculator to be removed. The same can be achieved by adding the properties to the "Resource" dimension. In this way, records full of NULL values, will not be written to the database.
Saturday, June 20, 2009
Tuesday, June 16, 2009
Product vs Core. Why use low level API ?
Sometimes I wish that product API would not raise errors, but just return numeric result with the error number. This is what happening in the core API.
For example, the W6PTimeIntervals is a simple product wrapper for the W6TimeIntervals core class. Interesting is the fact that W6TimeInterval is a core class, which is used in the product without a wrapper.
However, the following short example of code is an implementation of a method, which is sometimes needed when dealing with time intervals. The error handling is general and there is no need to deal with "end of list" error:
For example, the W6PTimeIntervals is a simple product wrapper for the W6TimeIntervals core class. Interesting is the fact that W6TimeInterval is a core class, which is used in the product without a wrapper.
However, the following short example of code is an implementation of a method, which is sometimes needed when dealing with time intervals. The error handling is general and there is no need to deal with "end of list" error:
Private Sub UnSetTimeIntervals( _
ByVal intervals As W6PTimeIntervals, _
ByVal unset As W6PTimeIntervals)
Try
Dim W6RC_MDL_TIME_INTERVALS_END_OF_LIST _
As Integer = 4120
Dim rc As Integer = 0
Dim timeInterval As W6TimeInterval
= New W6TimeInterval
' UnSet older intervals from the newer intervals,
' so only the new interval remains
rc = unset.RefW6TimeIntervals.GetFirst( _
timeInterval)
Do While (CatchRcExclude(rc, _
W6RC_MDL_TIME_INTERVALS_END_OF_LIST))
CatchRC( _
intervals.RefW6TimeIntervals.UnSetTimeInterval _
(timeInterval))
rc = unset.RefW6TimeIntervals.GetNext( _
timeInterval)
Loop
Catch ex As Exception
Call GeneralErrorHandling("UnSetTimeIntervals")
End Try
End Sub
Private Function CatchRcExclude( _
ByVal rc As Integer, _
ByVal exclude As Integer) As Boolean
If (rc = exclude) Then Return False
CatchRC(rc)
Return True
End Function
Private Sub CatchRC(ByVal rc As Integer)
If (rc = 0) Then Exit Sub
Dim errObject As W6ShPError = _
W6ShPErrorUtilities.W6CreateCoreError( _
rc, "", True, True)
End Sub
Tuesday, June 9, 2009
Add-in for custom report
When I was writing a custom ClickAnalyze report, I did not expect that the ClickSchedule client's wizard, which opens the report, will cause any troubles. But it was no ordinary report, and as such it did not include geography dimension (no region and no district). The wizard did not handle this well and actually I had to develop a simple add-in.
In order to create the add-in, I just needed to send SXP, Create the out-of-the-box form with the report viewer, and show it (well, it might be a bit more). And here is the code:
In order to create the add-in, I just needed to send SXP, Create the out-of-the-box form with the report viewer, and show it (well, it might be a bit more). And here is the code:
' This class should be visible to COM
Public Class W6CustomReportAddin
Public Function DoAddIn( _
ByRef objCallingApp As Object, _
ByRef objCallingDoc As Object, _
ByRef lDocType As Integer, _
ByRef varSelectedEngineers As Object, _
ByRef varSelectedTasks As Object, _
ByRef varSelectedAssignments As Object) _
As Boolean
Try
' Send SXP request and get the response
Dim request As Xml.XmlDocument = _
New Xml.XmlDocument
request.LoadXml( _
"<SXPServerReportProcess><Report>" & _
"<Name>Custom Report</Name>" & _
"</Report></SXPServerReportProcess>")
Dim conn As W6Logon.Connection = _
New W6Logon.Connection
Dim response As Xml.XmlDocument = _
conn.Send(request)
' Create the report viewer dialog and set
' the report properties
Dim dialog As W6ReportsClient.frmMainForm = _
New W6ReportsClient.frmMainForm( _
W6ReportsClient.ProductType.ClickSchedule)
Dim dataManager As _
W6ReportsClient.CW6DataManager = _
W6ReportsClient.CW6DataManager.GetInstance()
dialog.ReportsServerURL = _
dataManager.ReportServerURL
dialog.ReportPath = "/" & _
dataManager.RootFolder & "/" & _
dataManager.ClickScheduleFolderName & _
"/Day/Custom Report"
' Create client domain and set the instance id
Dim domain As _
W6ReportsClient.CW6ClientDomain = _
New W6ReportsClient.CW6ClientDomain( _
W6ReportsClient.ProductType.ClickSchedule)
domain.InstanceID = _
response.DocumentElement.SelectSingleNode( _
"InstanceID").InnerText
' Set the title and build the report
dialog.AddReportNameToTitle("Custom Report")
dialog.BuildReport(domain)
' Show the dialog as modal form
dialog.ShowDialog()
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Error")
End Try
End Function
End Class
Monday, June 8, 2009
When it's not DueDate anymore
Today we will focus on 2 "Click" products and more specifically, on one interaction point between them: ClickSchedule and ClickAnalyze.
I recently seen more and more projects that are using other Task properties than DueDate for fetching unscheduled tasks. Lets assume we have new user defined property (UDP), which represents the date that an unscheduled task should be scheduled (many times it is called OptimizeOnDate). I would like ClickAnalyze to use this new UDP instead of the DueDate in default conditions.
First, I change the setting of the Service Optimization Administration snap-in. I want to be able to edit the XML in the Body property of a specific setting object.
You can see I added the standard XML editing to Setting object with Category="Reports" and SubCategory="Components".
Now I can open the Components setting using standard XML editing, and manipulate the Body property directly.
I expand the components until I found the "Time Resolution" dimension.
You can see that it includes additional node after the "Type Specific Information" comment.
I expand the third OQL condition for the tasks collection.
Just to remind you, OQL stands for Object Query Language. This is the XML that is used in the group objects of the "Click" products.
I can spot that DueDate property is used twice (see red arrows).
In my customization, the ID of the OptimizeOnDate property is 105. So I changed both places and keep those changes.
Now I'm creating new report for ClickAnalyze Reporting.
I added "Count Objects" measure and named it Tasks.
You can see that the default condition for tasks is no longer on the DueDate property, but on the new OptimizeOnDate property.
You can use the same technique to have new OQL conditions for new collections that include date properties.
I recently seen more and more projects that are using other Task properties than DueDate for fetching unscheduled tasks. Lets assume we have new user defined property (UDP), which represents the date that an unscheduled task should be scheduled (many times it is called OptimizeOnDate). I would like ClickAnalyze to use this new UDP instead of the DueDate in default conditions.
First, I change the setting of the Service Optimization Administration snap-in. I want to be able to edit the XML in the Body property of a specific setting object.
You can see I added the standard XML editing to Setting object with Category="Reports" and SubCategory="Components".
Now I can open the Components setting using standard XML editing, and manipulate the Body property directly.
I expand the components until I found the "Time Resolution" dimension.
You can see that it includes additional node after the "Type Specific Information" comment.
I expand the third OQL condition for the tasks collection.
Just to remind you, OQL stands for Object Query Language. This is the XML that is used in the group objects of the "Click" products.
I can spot that DueDate property is used twice (see red arrows).
In my customization, the ID of the OptimizeOnDate property is 105. So I changed both places and keep those changes.
Now I'm creating new report for ClickAnalyze Reporting.
I added "Count Objects" measure and named it Tasks.
You can see that the default condition for tasks is no longer on the DueDate property, but on the new OptimizeOnDate property.
You can use the same technique to have new OQL conditions for new collections that include date properties.
Sunday, June 7, 2009
Starting new developers blog
For long time I wanted to start blogging about the "Click" products development. I guess that each time I tell someone about a nice feature or a better way to customize and develop for the "Click" products, I want to have a way to share it with more than just one developer. So, from now, this blog will include development ideas and tips for the "Click" products.
Now what if you are not familiar with those products? Go to ClickSoftware.com and learn about those products.
Now what if you are not familiar with those products? Go to ClickSoftware.com and learn about those products.
Subscribe to:
Posts (Atom)