The closest thing
that Dynamics CRM 2011 has to a notification is the concept of Announcements.
There are some drawbacks to Announcements, most important being that they
cannot be scheduled. Also, can we expect the user to keep going back to the
Announcements page each time to see the latest? I think not :)
1. Create a new custom entity
called "Notifications". Add the following fields:
2. Add javascript that will enforce the required fields in the Notifications record
There are a few
options that are available in the webosphere that could help. In this post, I
am going to talk about a solution to have custom html notifications which can be
scheduled to fire only at the appropriate time, as well as provide options on how to display the notification.
Business Case:
User should see the
notification only between certain date/times, with the content of the
notification itself coming from an html web resource. Options are needed for
scheduling and to define how the notification would display. If more than one
notification is valid, the order of the notification alert should be configurable.
Design:
We will be creating
a new entity call "Notifications" that is visible from the Settings
area. The notification record will have details of the start and end time/
duration (if applicable). The order of display is determined by the ordinal value
Implementation Details:
Field Name
|
Type
|
Required (Y/N)
|
Description
|
Name
|
Text
|
Y
|
Name of the record
|
Start Date/Time
|
DateTime
|
Y
|
Start date and
time for notification
|
End Date/Time
|
DateTime
|
Y
|
End date and time
for notification
|
Duration
|
Number
|
Y, unless Always
in selected as Recurrence
|
Duration of
notification in minutes
|
Modal dialog or
New Window
|
Boolean
|
Y
|
Shows the alert as
modal dialog, or as a new window
|
Recurrence
|
Drop Down
|
Y
|
Contains values
Always, One Time, Daily and Weekly
|
Recur Every
|
Drop Down
|
Y, If weekly is
selected
|
Contains values
with days of the week
|
Web Resource
|
Text
|
Y
|
URL for the html
page
|
Ordinal Value
|
Number
|
N
|
Defines order of
notification
|
2. Add javascript that will enforce the required fields in the Notifications record
//function to set the value of Recur Every fields as required if Weely is selected as the transfer reason. Fires on onchange of Recurrence, and onload of form function setReqFields() { var rc1 = Xrm.Page.getAttribute("new_recurrence").getValue; if (rc1 != null) { var recurrence = Xrm.Page.getAttribute("new_recurrence").getSelectedOption().text; if (recurrence == "Weekly") { Xrm.Page.getAttribute("new_recurevery").setRequiredLevel("required"); } else { //set recur every field to not required Xrm.Page.getAttribute("new_recurevery").setRequiredLevel("none"); } //duration is required unless recurrence is of type Always if (recurrence != "Always") { Xrm.Page.getAttribute("new_durationinminutes").setRequiredLevel("required"); } else { //set recur every field to not required Xrm.Page.getAttribute("new_durationinminutes").setRequiredLevel("none"); } } }
//function to get values from the crm Notification entity - onload of Phone call form function getNotifications() { var formType = Xrm.Page.ui.getFormType(); //notification only for updates if (formType == 2) { var serverUrl = Xrm.Page.context.getServerUrl(); var today = new Date(); var jsonText = JSON.stringify(today); jsonText = jsonText.replace(/\"/g, ''); //alert(jsonText); //The XRM OData end-point var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc"; var odataSetName = "new_notificationSet"; //get all notifications that have the end date greater than current date var odataSelect = serverUrl + ODATA_ENDPOINT + "/" + odataSetName + "?$orderby=new_OrdinalValue&$filter=new_EndDateTime gt datetime\'" + jsonText + "\'"; //alert(odataSelect); $.ajax({ type: "GET", contentType: "application/json; charset=utf-8", datatype: "json", url: odataSelect, beforeSend: function (XMLHttpRequest) { XMLHttpRequest.setRequestHeader("Accept", "application/json"); }, success: function (data, textStatus, XmlHttpRequest) { //alert(data.d.results.length); if (data.d.results && data.d.results != null) { for (var indx = 0; indx < data.d.results.length; indx++) { //alert("Name – " + data.d.results[indx].new_name); notificationName = data.d.results[indx].new_name; //get notification values var recurrence = eval(data.d.results[indx].new_Recurrence.Value); var windowType = eval(data.d.results[indx].new_NotificationDisplay.Value); var webresource = data.d.results[indx].new_Webresource; var startDate = data.d.results[indx].new_StartDateTime; startDate = startDate.replace(/\//g, ''); startDate = startDate.replace("Date(", ''); startDate = startDate.replace(")", ''); var sd = new Date(Number(startDate)); var endDate = data.d.results[indx].new_EndDateTime; endDate = endDate.replace(/\//g, ''); endDate = endDate.replace("Date(", ''); endDate = endDate.replace(")", ''); var ed = new Date(Number(endDate)); var duration = data.d.results[indx].new_DurationinMinutes; var de1 = new Date(Number(startDate)); var durationEnd = de1.setMinutes(de1.getMinutes() + Number(duration)); var de = new Date(Number(durationEnd)); //recurrence - change the option set values based on yours if (recurrence == 912630000) { //alert("always"); always(sd, ed, today, windowType, webresource); } else if (recurrence == 912630001) { //alert("one-time"); notification(sd, today, de, windowType, webresource); } else if (recurrence == 912630002) { //alert("daily"); sd.setFullYear(today.getFullYear()); sd.setDate(today.getDate()); sd.setMonth(today.getMonth()); de.setFullYear(today.getFullYear()); de.setDate(today.getDate()); de.setMonth(today.getMonth()); notification(sd, today, de, windowType, webresource); } else if (recurrence == 912630003) { //alert("weekly"); //get last character of the option set var recurEvery = eval(data.d.results[indx].new_RecurEvery.Value).toString(); recurEvery = recurEvery.charAt(recurEvery.length - 1); if (today.getDay().toString() == recurEvery.toString()) { //alert("call weekly"); sd.setFullYear(today.getFullYear()); sd.setDate(today.getDate()); sd.setMonth(today.getMonth()); de.setFullYear(today.getFullYear()); de.setDate(today.getDate()); de.setMonth(today.getMonth()); notification(sd, today, de, windowType, webresource); } } } } }, error: function (XmlHttpRequest, textStatus, errorThrown) { alert('OData Select Failed: ' + odataSelect+" Error thrown: "+errorThrown+" Status: "+textStatus); } }); } } function notification(startDate, todayDate, durationEnd, windowType, webresource) { if (todayDate.getTime() > startDate.getTime() && todayDate.getTime() < durationEnd.getTime()) { if (windowType == 912630000) { //modal window var myWin = window.showModalDialog(webresource); } else if (windowType == 912630001) { //new window var myWin = window.open(webresource, 'Notification'); myWin.focus(); } } } function always(startDate, endDate, todayDate, windowType, webresource) { if (todayDate.getTime() > startDate.getTime() && todayDate.getTime() < endDate.getTime()) { //alert("always"); if (windowType == 912630000) { //modal window var myWin = window.showModalDialog(webresource); } else if (windowType == 912630001) { //new window var myWin = window.open(webresource, 'Notification'); } } }
Let
me walk through the code a bit here. The first step is to create the odata url
to return all notifications that are active (i.e, current date/time is before
the End Date/time) and ordered by the ordinal value. Once we get the active
notifications, depending on the recurrence option set value, either function
"notification" or "always" is called.
Within
function "notification" or "always", depending of the type
of notification display, the webresource is shown as a new window, or as a
modal dialog.
If
recurrence is set to "Always", the notification happens if current
Date/time is within start and end date/times.
If
recurrence is set to "One Time", the notification happens if current
Date/time is within (start date/time) and
(start date/time + duration).
If
recurrence is set to "Daily", the notification happens if current
Date/time is within (start time) and
(start time + duration).
If
recurrence is set to "Weekly" and current day equals the "Recur
Every" day, the notification happens if current Date/time is within (start time) and (start time + duration).
Note:
The "Recur Every" option set has values for the days, starting from
Sunday which has value of 912630000. JS date.getDay() function returns the
value of the week, starting with 0 for Sunday. Since odata calls do not get the
value of the option set text value, I worked around it by getting the value of
the last character of the option set, and comparing it with the getDay
function.
Here is an example
of a daily notification between 10 am and 11 am (10 am + duration time):
Here is an example
of the notification that displays when the
account record is opened and if the current time is between 10 am and 11
am, warning the user not to update the account details.
Conclusion:
In this post I have
laid out a pretty easy way to setup your user alerts, and have it configured by a manager/ admin. The nice thing is the notification content itself is
outside of the js code, and can be setup as a webresource with all the
style/design options available in html.
You would effectively "turn off" an existing notification alert by moving the end date/time to before the current date/ time.
You would effectively "turn off" an existing notification alert by moving the end date/time to before the current date/ time.
Note that he admin will need
read/ write privilege to the notification entity to create new notifications,
while the other users need read privilege to the notification object to pull in
the list of active notifications.
Thanks for reading!
Great post. I really appreciate your work. Thanks for sharing.
ReplyDeletedesktop notification software