ServiceNow: How to create a workflow that runs on incident update? - servicenow

I need to create a workflow which runs any time an incident is created or updated (or one workflow for each).
When I create a workflow and set the "Table" to Incident, it will run every time an incident is created, but it doesn't run when an incident is updated. I've searched through the wiki and read a slideshow talk on workflow creation, but so far no dice.
Thanks.

You would need to create a business rule on the Incident table that would call your workflow each time there is an update:
var updateOwner = new GlideRecord('wf_workflow');
updateOwner.addQuery('name', '<workflow_name>');
updateOwner.query();
if (updateOwner.next()) {
var wf = new Workflow();
var workflowId = '' + updateOwner.sys_id;
var vars = {};
wf.startFlow(workflowId, current, current.operation, vars);
gs.addInfoMessage('Workflow initiated.');
}

Related

Plugin performance in Microsoft Dynamics CRM 2013/2015

Time to leave the shy mode behind and make my first post on stackoverflow.
After doing loads of research (plugins, performance, indexes, types of update, friends) and after trying several approaches I was unable to find a proper answer/solution.
So if possible I would like to get your feedback/help in a Microsoft Dynamics CRM 2013/2015 plugin performance issue (or coding technique)
Scenario:
Microsoft Dynamics CRM 2013/2015
2 Entities with Relationship 1:N
EntityA
EntityB
EntityB has the following columns:
Id | EntityAId | ColumnDemoX (decimal) | ColumnDemoY (currency)
Entity A has: 500 records
Entity B has: 150 records per each Entity A record. So 500*150 = 75000 records.
Objective:
Create a Post Entity A Plugin Update to "mimic" the following SQL command
Update EntityB
Set ColumnDemoX = (some quantity), ColumnDemoY = (some quantity) * (some value)
Where EntityAId = (some id)
One approach could be:
using (var serviceContext = new XrmServiceContext(service))
{
var query = from a in serviceContext.EntityASet
where a.EntityAId.Equals(someId)
select a;
foreach (EntityA entA in query)
{
entA.ColumnDemoX = (some quantity);
serviceContext.UpdateObject(entA);
}
serviceContext.SaveChanges();
}
Problem:
The foreach for 150 records in the post plugin update will take 20 secs or more.
While the
Update EntityB Set ColumnDemoX = (some quantity), ColumnDemoY = (some quantity) * (some value) Where EntityAId = (some id)
it will take 0.00001 secs
Any suggestion/solution?
Thank you all for reading.
H
You can use the ExecuteMultipleRequest, when you iterate the 150 entities, save the entities you need to update and after that call the request. If you do this, you only call the service once, that's very good for the perfomance.
If your process could be bigger and bigger, then you should think making it asynchronous as a plug-in or a custom activity workflow.
This is an example:
// Create an ExecuteMultipleRequest object.
requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior: continue on error, return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
// Add a UpdateRequest for each entity to the request collection.
foreach (var entity in input.Entities)
{
UpdateRequest updateRequest = new UpdateRequest { Target = entity };
requestWithResults.Requests.Add(updateRequest);
}
// Execute all the requests in the request collection using a single web method call.
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithResults);
Few solutions comes to mind but I don't think they will please you...
Is this really a problem ? Yes it's slow and database update can be so much faster. However if you can have it as a background process (asynchronous), you'll have your numbers anyway. Is it really a "I need this numbers in the next second as soon as I click or business will go down" situation ?
It can be a reason to ditch 2013. In CRM 2015 you can use a calculated field. If you need this numbers only to show up in forms (eg. you don't use them in reporting), you could also do it in javascript.
Warning this is for the desesperate call. If you really need your update to be synchronous, immediate, you can't use calculated fields, you really know what your doing etc... Why not do it directly in the database? I know this is a very bad advice. There are a lot of reason not to do it this way (you can read a few here). It's unsupported and if you do something wrong it could go really bad. But if your real situation is as simple as your example (just a calculated field, no entity creation, no relation modification), you could do it this way. You'll have to consider many things: you won't have any audit on the fields, no security, caching issues, no modified by, etc. Actually I pretty much advise against this solution.
1 - Put it this logic to async workflow.
OR
2 - Don't use
serviceContext.UpdateObject(entA);
serviceContext.SaveChanges();.
Get all the records (150) from post stage update the fields and ExecuteMultipleRequest to update crm records in one time.
Don't send update request for each and every record

Can Reminder be updated for windows phone

Would appreciate you help for the following.
I have created a reminder but I want to update it before or after the reminder nofiticaton has activated. here the code.
Problem : it wont work even if there is no compilation error for this code.
var Myreminders = ScheduledActionService.GetActions()
.Where(a => a.BeginTime.Month == month);
foreach (Reminder r in Myreminders)
{
string strMyRmd;
strMyRmd = r.Name.ToString();
if ( strMyRmd == "MyName1" )
{
r.Title = "Today Shopping";
}
}
Thanks
I believe (I can't test this from my computer but have confirmed this works with Background Agents) that you need to find your Reminder, remove it from the scheduled action service, update and re add it.
var reminder = (Reminder)ScheduledsActionService.Find("MyReminder");
ScheduledActionService.Remove("MyReminder");
reminder.Title = "Updated Title";
ScheduledActionService.Add(reminder);
According to the remarks section in ScheduledActionService.GetActions Method documentation page:
The Scheduled Action Service does not maintain a reference to the
objects returned by this method, and therefore the properties of the
objects are not updated to reflect the current state after the call to
GetActions. To obtain an object that is updated by the system as its
state changes, use Find(String) instead.
So, just use Find(String) instead.

updateEntity["new_totalsum"] = new CrmMoney(calculatedvalue);

I can not update the webform. To bee updated I have to push the save button two times. I´ve tried with DynamicEntity entity = (DynamicEntity)context.PreEntityImages["PreCalculate"]; DynamicEntity updateEntity = (DynamicEntity)context.InputParameters.Properties["Target"];
... updateEntity["new_totalsum"] = new CrmMoney(calculatedvalue); The problem is it will not bee updated the first time I push the save button. I have registred the image PreCalculate as Preimage and Message: Update; Eventing Pipeline Stage of Excecution: Pre Stage; Execution Mode : Syncronous
What´s wrong? Thanks
You need to write the modified record back into the Target when you're done, so your changed values will be used when writing the record to the database. At the end of your plugin's Execute() method, do
context.InputParameters[ParameterName.Target] = updateEntity;

How to manually load an entity as well as a related entity

I have two entity objects one that holds billing address information(TBLADDRESS) and one that holds my account addresses(TBLMYACCOUNTADDRESS).
At a point in my project i need to load the TBLADDRESS object with the corresponding values from TBLMYACCOUNTADDRESS. Both of which have a relation to LKSTATE.
My problem is i cannot populate this related entity manually. Maybe it's not possible?
Here is my script so far, hopefully it will help you better understand exactly what i am trying to accomplish:
TBLADDRESS tblBilling = new TBLADDRESS();
TBLMYACCOUNTADDRESS myAccountDefaultAddress = new TBLMYACCOUNTADDRESS();
myAccountDefaultAddress = myAccountAddress.FindAll(delegate(TBLMYACCOUNTADDRESS i) { return i.IS_DEFAULT == true; }).ToList().SingleOrDefault();
tblBilling = new TBLADDRESS();
tblBilling.FIRST_NAME = myAccountDefaultAddress.FIRST_NAME;
tblBilling.LAST_NAME = myAccountDefaultAddress.LAST_NAME;
tblBilling.COMPANY = myAccountDefaultAddress.COMPANY;
tblBilling.ADDRESS_1 = myAccountDefaultAddress.ADDRESS_1;
tblBilling.ADDRESS_2 = myAccountDefaultAddress.ADDRESS_2;
tblBilling.CITY = myAccountDefaultAddress.CITY;
tblBilling.LKSTATE.STATE_ID = myAccountDefaultAddress.LKSTATE.STATE_ID;
tblBilling.POSTAL_CODE = myAccountDefaultAddress.POSTAL_CODE;
tblBilling.PHONE = myAccountDefaultAddress.PHONE;
Question is how would i go about populating the tblBilling.LKSTATE.STATE_ID manually. Currently i get an object reference not set to an instance of an object error message, but something tells me there's more to it than that.
Thanks in Advance,
Billy
Figured it out.
All i need was the instance of the object created before assigning to it.
tblBilling.LKSTATE = new LKSTATE();
Initially i wasn't sure just how to create the instance. Pretty straightforward.

How do I retrieve just recurring event masters using Exchange Web services?

I'm using a CalendarItemType view to retrieve calendar items. The only items I care about are those that I've created and I know that they are all weekly recurring items. I'm able to get each individual occurrence and, from any one of them the recurring master item, but I'd like to narrow the scope of my search to just those items that would match my pattern.
I've trying using the Restriction property on the FindItemType to specify a NotEqualTo restriction with a null constant for calenderRecurrenceId. This caused my request to time out. So far I've been unable to load the recurrences with the FindItemType at all and need to use a subsequent GetItemType call when I find an event that is an occurence in a recurring series.
Here's the code that I'm starting with. The code needs to work with both Exchange 2007 and Exchange 2010.
var findItemRequest = new FindItemType();
findItemRequest.ParentFolderIds = new DistinguishedFolderIdType[]
{
new DistinguishedFolderIdType()
};
((DistinguishedFolderIdType)findItemequest.ParentFolderIds[0]).Id = DistinguishedFolderIdNameType.calendar;
findItemRequest.Traversal = ItemQueryTraversalType.Shallow;
var itemShapeDefinition = new ItemResponseShapeType(
{
BaseShape = DefaultShapeNamesType.AllProperties;
}
findItemRequest.Item = calenderView;
findItemRequest.ItemShape = itemShapeDefinition;
var findItemResponse = this.esb.FindItem( findItemRequest );
Also, if you know of any good source of examples (beyond the ones in MSDN), I'd welcome them. I'm picking up someone else's code in an emergency and trying to learn Exchange Web Services on the fly.
Maybe I'm misunderstanding you, in which case I apologize.
You do NOT use the CalendarView - you use the normal IndexedPageItemView if all you want is Master Recurring Calendar items.
You use the CalendarView to expand the recurrences to individual items. However the compromise with CalendarView is NO restrictions are permitted besides Start and End Date. None.
You can search for a RecurrenceMaster by using the recurrence PidLid with an ExtendedPropertyDefinition. This works because, according to their documentation, "this property must not exist on single instance calendar items."
https://msdn.microsoft.com/en-us/library/cc842017.aspx
// https://msdn.microsoft.com/en-us/library/cc842017.aspx
ExtendedPropertyDefinition apptType = new ExtendedPropertyDefinition(
DefaultExtendedPropertySet.Appointment,
0x00008216, //PidLidAppointmentRecur
MapiPropertyType.Binary);
var restriction = new SearchFilter.Exists(apptType);
var iView = new ItemView(10);
var found = folder.FindItems(restriction, iView);
I just confirmed this works, today, when revisiting some old code that works with Office365 EWS in the cloud.
Found only property you need is RecurrenceStart property. Because EWS has limitations it is not possible to use all properties in restriction. This one working as expected.
Reference: Find master recurring appointments
You can create custom searchfilters. If you search from specific startdate OR isRecurring property you have most easy way...(SearchItems returns recurring masters)
List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
SearchFilter.IsGreaterThanOrEqualTo startDatumFilter = new SearchFilter.IsGreaterThanOrEqualTo(AppointmentSchema.Start, new DateTime(2012, 9, 16));
SearchFilter.IsEqualTo masterRecurringFilter = new SearchFilter.IsEqualTo(AppointmentSchema.IsRecurring, true);
searchFilterCollection.Add(startDatumFilter);
searchFilterCollection.Add(masterRecurringFilter);
SearchFilter finalFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection);
ItemView itemView = new ItemView(100000);
itemView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties, AppointmentSchema.AppointmentType);
FindItemsResults<Item> items = _service.FindItems(WellKnownFolderName.Calendar, finalFilter, itemView);

Resources