Introduction
Hello!
I want to share the experience of automating a single business process on the Sharepoint 2010 platform.
I think this article will be interesting first of all to those users who for some reason do not want to write code in Visual Studio. It’s about how you can get around the limitations of regular SharePoint functionality using various available solutions.
Experience with the automation of various processes in the company allowed me to identify a fairly popular business process, maybe it even has some name, unless of course there is a similar classification. This is a basic process that can have various derivatives that differ in details, for example:
- The system of coordination of marketing actions - the region offers the implementation of the action and then it goes through a sequence of approvals and additions - right up to the center. Each step is combined with instructions for specific users. Ultimately, the share may be sent for sale or rejected.
- The system of collecting ideas from employees - the employee offers an idea and then can observe how it goes through the sequence of improvements and approvals - right up to the moment it is accepted for work, or returned for revision
- ... and many, many similar ones: working with problems, bugs and incidents, working with claims, working with assets - in a word, any task that requires consistent consideration by several users to make a decision.
The mechanism of all such systems is approximately the same: in general, a list is needed to store the main entities: action, idea, order, problem, etc. Next - you need a list of tasks for the formation of instructions. In addition, you probably need a number of reference lists, such as statuses, roles, regions, branches, etc.
The platform has everything you need for this: the ability to quickly build lists for basic data, assignable tasks and directories, users already synchronized with AD, a ready access distribution mechanism and much more. However, in order to fully automate the process and do without a coordinator, whose task is to assign tasks, tasks, process answers and transfer our essence from status to status — for this, at least, you need to use workflows — workflow. Let's start with them.
Formulation of the problem
We will consider a special case of a business process - let's call it “Orders for regulatory procedures”
In short: there is a list of ready-made generally accepted regulatory procedures - Regulations. Nobody has direct access to the direct creation, modification or deletion of the elements of this list of procedures, but any user can suggest creating, changing or deleting a procedure.
In order for this to happen, he creates a so-called Order. An order passes a certain sequence of status steps, each of which assigns assignments to certain roles. The order with which the order will be transferred depends on which decision the order is closed with. In addition, the sequence of steps is individual for orders to create, modify and delete, and also depends on an additional feature express, which allows you to pass the Order in a simplified manner. Thus, at each step, where the order goes will depend on three conditions: on its type, on the presence of the express feature and on the user's decision.
When the Order passes the chain of approvals and additions, the corresponding Regulations will automatically be created / changed / deleted.
')
General solution architecture
Main lists created for solving the problem:
- Regulations
- Orders
- Tasks
- ... + Various directories
Process flow:

Process automation
The screenshot below is a similar scheme made using Visio

It can be exported to MS SharePoint Designer - a workflow will be automatically created with “if ... then ...” conditions and tasks for users, but even this simplified scheme looks quite cumbersome. Especially if you take into account the fact that at almost every step of the order you need to perform additional activities - for example, send a letter, in some steps you need to make changes to other lists. This makes a linear workflow (and SP Designer allows you to make only linear) difficult to apply to our situation.
To solve this problem, you can use this combination of two workflows, let's call it a “ring”:

The workflow “ring” successfully replaces the linear workflow.
The idea is simple - we already have 2 lists, a list of orders and a list of tasks. We place an uncomplicated workflow on the list of orders, which looks at the current status of the Order and, depending on this, creates a particular task. We add an even more simple workflow to the task list, which, when the task is completed, updates the status in the linked Order, thereby initiating the re-execution of the workflow on the Order.
In order not to describe all the steps and transitions directly in the body of the workflow, we will create several more reference lists:
- tasklist - a list of all possible tasks assigned to users during the transition to the next step
- logicoftransitions - transition logic. List consisting of fields:
- taskfrom - the task from which to perform the transition
- condition1 - condition 1 (in our case, this decision is Yes or No, taken by the user on the previous task)
- condition2 - condition 2 (in our case, the presence or absence of the “express” feature)
- condition3 - condition 3 (in our case, the order type is RP creation, RP change, RP removal)
- taskto is a task to which the process should be transferred taking into account the previous conditions
- sendemail - the field Yes / No, whether to send a letter when the condition
- emailsubj - letter subject
- emailtext - letter text
- emailsendto - email recipients
These lists are enough to automate the process. Of course, if we leave the taskfrom field empty, this will mean that the task is the first and has no previous tasks. An empty taskto field means the absence of the next step - a task, and if you need to do something besides sending a letter, this situation must be further processed in the body of the workflow.
The final workflow on the Orders list is quite short - judge for yourself (the picture is divided into 2 halves):

The workflow for the Tasks list contains only one activity at all.

There is another nuance. In the workflow, you cannot just pick up and select an item from the list if several fields match. One matching field is please, but no more. However, the problem is solved in an elegant way. We need to hang a small workflow or handler, or even just a calculated field on a list of logicoftransitions — its task will be to simply fill in a hidden text field, which we will use for comparison. So, for example, if a step depends on the state 'task name', solution 'yes / no', 'express sign' and 'order type', then the line will look like, for example, 'manager-yes-yes-creation of order'. In the main workflow, there is a conditionstring variable, and we will compare it with our field.
Advantages of such a decision:
+ It’s enough to make a blank node once, and turning it into a working node to automate a particular business process in the future will take quite a bit of time.
+ It is very easy to change the trajectory of the order - no need to change the workflow itself, just change the reference values ​​in the tasklist and logicoftransitions.
+ with the condition of minor refinement, you can realize the ability for the user to jump into an arbitrary step, or even assign individual trajectories to individual orders.
Minuses:
- you cannot look at the beautiful chart, where our order is currently located, how this can be done if you use the regular linear workflow
In order to at least partially neutralize this drawback, you can display all related tasks in the DispForm, an order viewing form. This will give a clear picture of the step at which the order is at the moment and the data from which user (s) are expected. This is done simply: we want the tasks to be tied to the order — it is enough to assign the value of the ID of the current element to the “Order” substitution field. It’s also easy to display them in the Order View Form; you just need to add a web part to the DispForm for the Orders list, a web form with a filter that displays the elements of the task list with the value of the lookup field: ID equal to the parameter taken from the browser's request string.
Creating related list items (Order linked to the Regulations). Autocomplete and hide fields.
As follows from the terms of reference, it is necessary to be able to create Orders for changing and deleting Regulations. To do this, obviously, the order must be tied to the Regulations.
The wish of the customer of the system was auto-completion of the fields in these newly created orders - the fields from the Regulations were to be transferred to the Order.
One of the tried ways was to create a finished Order by a workflow, and send the user a link to the resulting Order. However, this practice has shown its inefficiency - the user does not want to be distracted by mail, he wants to see the Order being created on the screen with the possibility of making changes before it is created.
Such a solution was invented. We use the same Sharepoint Designer. A new form is created for viewing the list of the Regulations, and it is desirable to create it by cloning the existing file DispForm.aspx
Then, under the form that displays all the fields, create a form for creating a new item in the Orders list. Thus, we have one form, in the upper part of which there are fields in the view mode, in the lower part - in the fill mode.
To fill use the good old javascript. The script code can be placed on our * .aspx - page after the line:
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
or in the new web part of the Content Editor located under all other web parts.
Step one: take the value from the fields in the top web part. The caveat is that these fields have the same id. So, for example, if we have several fields with the “Single-line text” type - they all will have the id “SPFieldText” This of course makes it difficult to find the desired value, and here is one of the ways to solve this problem:
Now we have in the array element al [0] - the contents of the first tag with id “SPFieldNumber”, in al [1] - the second, and so on ...
Step number two: write the values ​​in the appropriate fields. In the editing form, unlike the viewing form, all fields have a unique id (by the way, you can view it in IE by clicking F12, then selecting the desired field with the search cursor):

Each type of field requires its own individual approach, for example, for fields with the type “Single line text” and “Select” the contents of the tag look like this:
<td valign="top" class="ms-formbody" width="450px" id="SPFieldText"> </td>
and the values ​​from the contents of the tag can be taken as follows:
For a field with “Substitution” type, the contents of the tag look like this
<td valign="top" class="ms-formbody" width="450px" id="SPFieldLookup"> <a href="/it/d/dpp/nmc/Lists/InstanceForis/DispForm.aspx?ID=6&RootFolder=*"> ​</a> </td>
we only need the ID value, we can get it using regular expressions, like this:
lp0 = lp[0].innerHTML; var r = /ID=(\d+)/ig if ( r.test( lp0 ) ) { res = lp0.match( r ) lp0 = RegExp.$1 }
Now you need to set the “Substitution” field to the desired value - there is quite a voluminous code, several functions are used, taken from here:
http://blogs.msdn.com/b/sharepointdesigner/archive/2007/06/13/using-javascript- to-manipulate-a-list-form-field.aspxThese functions are copied to our page as is, unchanged. After that, in order to set the “Substitution” field to a value, just write, for example:
setLookupFromFieldName(" ", lp0);
or
setLookupFromFieldName(" ", vals["ID"]);
Thus, our Order becomes attached to the Regulations.
Sometimes some fields need to be set to the desired values ​​explicitly. For example, for the “Yes / No” field:
document.getElementById("ctl00_m_g_41362970_e9f4_429e_b60f_f62d1e52e332_ff3_new_ctl00_ctl00_BooleanField").checked=false;
Further, some fields need to be hidden in order to avoid changes by the user. In our case, these are the fields “Related regulations” and “Order type”.
To hide the fields for us there is a great solution in the jQuery library. It is enough to connect these libraries, indicating the path to them as follows:
<script language="javascript" type="text/javascript" src="/jQuery%20Libraries/jquery-1.6.1.min.js"></script>
and now, in order to hide the line from the user, such a construction is enough:
$('#ctl00_m_g_41362970_e9f4_429e_b60f_f62d1e52e332_ff24_new_ctl00_Lookup').closest('tr').hide();
It would be wrong not to mention here about SPServices - a jQuery-based library written specifically for Sharepoint. It was not useful in this project, but nevertheless there are a lot of useful functions. For example, $ (). SPServices.SPCascadeDropdowns - allows you to filter drop-down values ​​of the “Substitution” field depending on the selection in the previous fields and many other utilities. Project address:
http://spservices.codeplex.comValidation of entered fields
In SharePoint, there is an indication that the field is mandatory / optional and the ability to specify a formula for checking input values.
Sometimes a regular field verification mechanism is not enough. For example, if you want to make the input value dependent on other values.
To implement field validation, you can use the capabilities of the SharePoint Power EventReceiver 2010 solution taken from here
http://ilovesharepoint.codeplex.com/releases/view/55733The installed solution adds 2 additional menu items to the list:

and allows you to write powershell code for any event handler. In the case when we need to check the correctness of the input values, we need to define the ItemAdding and ItemUpdating functions.
To do this, simply uncomment them and write code like this:
function ItemUpdating{ if( $properties.AfterProperties["_x0413__x0440__x0443__x043f__x04"] -eq 0 ) { $atmsg=" ; " $warcnt=$warcnt+1 } if(($properties.AfterProperties["xpress"] -eq "true") -and ($warcnt)) { $properties.ErrorMessage = "<b> :</b><br>$atmsg<br> )" $properties.Cancel = $true } }
Be careful with the insidious Before- and AfterProperties, you can read more about them here:
gandjustas.blogspot.com/2011/05/blog-post.htmlRestriction of access to close the task, notifications about the overdue task.
Initially, in the newly created Tasks list, you can assign a task to only one person - however, this is easy to change, just by changing the “Can contain several values” property for the “To whom” field
It is more difficult to solve another moment - how to allow the task to be changed only to those users to whom it is directly assigned? In SharePoint Designer there is an activity “Give permissions to a list item” - it is available in the so-called “Impersonation Step”, in which all activities are performed on behalf of the creator of the workflow. However, this activity does not work with a field in which we have several users - it works only for one.
Here you can use another solution from the creator of Power EventReceiver 2010 - it is called Advanced Workflow Actions for SharePoint Designer 2010, located at
http://ilovesharepoint.codeplex.com/wikipage?title=Workflow%20Actions%20for%20SharePoint%20Designer%202010&referringTitle = Documentation and allows you to perform additional activities in our workflow. We are interested in the activity of Execute PowerShell Script - we will use it to divide the contents of the field “To whom is assigned” into components - into separate users.
Here is how the activity in workflow looks like (we start on creating a new task):

But its code is quite simple thanks to powershell:

Clearly, the limitation of this solution is a maximum of 5 users. This is usually more than enough.
Finally, how to organize notification of the user about the expiration of the task (or about the approaching of this period, or that the task expired 2 days ago - or about everything together) - one more workflow is needed with the activity “Take a pause until ...” wait for the desired date and send an alert.
Redirect to the desired page
From time to time it is required to redirect the user to any page by clicking the “Save” button.
If it is always the same link, then simply delete the standard button and create your own with a code like this:
<input type="button" value="" name="btnFormAction" onclick="javascript: {ddwrt:GenFireServerEvent('__commit;__redirect={../orderz/myorders.aspx}')}" />
If the direction of the redirect depends on the selected fields, then the same Power EventReceiver 2010 will help. The code will look like this:
function ItemAdding{ if ($properties.AfterProperties["reqtype"] -eq " ") { $properties.Status = [Microsoft.SharePoint.SPEventReceiverStatus]::CancelWithRedirectUrl $properties.RedirectUrl = "../orderz/NewForm.aspx" } else { $properties.Status = [Microsoft.SharePoint.SPEventReceiverStatus]::CancelWithRedirectUrl $properties.RedirectUrl = "../regproc" } }
Restricting access to create / modify without permissions
The user is not allowed to create, modify, or delete items in the Regulations list, however, if he is deprived of his permission to perform these actions, the workflow will not be able to do these operations (unless of course these actions are not performed in the impersonation step - but in this case the author will be which is not always convenient)
One solution is to simply make new forms for the list - instead of the traditional NewForm, EditForm, create new ones, tick the “default” checkbox on them and remove all the edit fields from there, replacing them with some text that explains why the user should create / delete Regulations can not be directly and what should be done instead - with links and instructions.
Conclusion
Of course, for the final delivery of the project, the customer still needs some “polishing” actions - hiding some fields, creating custom workstations with setting up views and menus depending on the role in the process. However, I listed the main “tricks” in the article, I really hope that they will be useful to someone.