sharepoint 2013 workflow copy list item to another site - FULL TUTORIAL

This also works for SP2016, and most likely 2019.

There are quite a few tutorials out there, but each missing a step, so this is going to be a full one top to bottom.

I will make a rich tutorial with pictures, but lets review the steps, and how its done.

Workflows doesn't have a way to copy list items to another site, so you need to make an HTTP Request for that, with the Rest API. Also Workflows can't build really JSON objects, so we will need to create Workflow Dictionaries.

1. Have a source list on site A, and a destination list on site B, and open SharePoint Designer 2013 on site A.
2. Learn and test Rest request for adding an item.
3. Build our Workflow, and lets not forget to make the Request as an "App Step"
4. Enable site feature for app step
5. Give the app permissions on site B
6. Run on Item Created (for the example)
7. Error Handling

So lets go!



1. Have a source list on site A, and a destination list on site B, and open SharePoint Designer 2013 on site A.

Well, really, I won't go deeply through that, you should have 2 sites, can be even root and a subsite, each a list, doesn't really matter what list and what columns.

In my tale, those are almost identical lists, the subsite have another 2 date fields and a boolean to decide should we copy to root. They are simple Events lists, Title, Description, Start DateTime, End DT.


2. Learn and test Rest request for adding an item.

I expect you to have understanding about what is Rest, Ajax, What is SP REST API, and how to post and item with it. For the example, and for help with some extra columns I'll add my code here.

remember that for the exact __metadata value you must put this url in your browser:
<site_url>/_api/web/lists/GetByTitle('<list_title>')?$select=ListItemEntityTypeFullName

function postAjax(url, jsondata, success) {

    let xhr = new XMLHttpRequest();
    xhr.open('POST', url);
    xhr.onreadystatechange = function() {
        if (xhr.readyState>3 && xhr.status==200) { 
           success(xhr.responseText); 
        }
    };

 //will not be needed in WF
    xhr.setRequestHeader('X-RequestDigest', 
                         document.getElementById('__REQUESTDIGEST').value);
    xhr.setRequestHeader('Accept', 'application/json;odata=verbose');
    xhr.setRequestHeader('Content-Type', 'application/json;odata=verbose');
    xhr.send( JSON.stringify(jsondata) );
    return xhr;
}

d = new Date();
d.setDate(d.getDate() + 15);

eventData = {
 //put <site_url>/_api/web/lists/GetByTitle('<list_title>')
 //?$select=ListItemEntityTypeFullName
 //to get the EXACT ListItemEntityTypeFullName value (CTRL+F)
 __metadata:{'type':"SP.Data.EventsListItem"} ,
 Title: "test rest event",
 EventStartDateTime : new Date().toISOString(),      
 EventEndDateTime    : d.toISOString(),
 EventDescription    : "i come from rest",
 BImage         : { 
  'Url' : "http://someurl", 
  'Description' : "not really an image url" 
 },
 SourceSite    : "Rest"
};
 
postAjax("/_api/web/lists/GetByTitle('bEvents')/items", eventData, 
  function(resTxt){ 
 console.log( JSON.parse(resTxt) ); 
  });


And the results:





3. Build our Workflow, and lets not forget to make the Request as an "App Step"

This is a long, boring part, that for the 1st time is going to be annoying, so i advise you to make a simple call with a simple list, with only title, just to taste that it works.

1. Open SharePoint Designer 2013 at your source site url
2. Click on Lists And Libraries and click on your source list

3. Click on List Workflow in the ribbon






4. Now for the hard part, you must build some Dictionaries for your HTTP Request, currently if you make a simple request its :

a. http headers, includes "Accept" and "Content-Type" with value of "application/json;odata=verbose"
b. item metadata, "__metadata" with value of  "SP.Data.WhateverListItem"
c. item data, key "type" value item metadata, and key "Title" with value of your title.

If its a big list with many columns you must copy them 1 by 1, and with complex columns like URL field you need to make another dictionary for that ( __metadata - type : SP.FieldUrlValue );

You can also take a look here for more details and English images, unfortunately my images are in Hebrew.



As you will try to Publish the WF you will get an error about having an App Step ect.


4. Enable site feature for app step


Go to Site Settings -> Manage site features and activate "Workflows can use app permissions".

To find your new app id go to Site Settings -> Site app permissions and your id is the 1st GUID, after the 2nd pipe until the @




5. Give the app permissions on site B

This is not enough, that only means that the step have permissions for site A, and we need to give it permissions for site B.

So, as deeply explained here, just jump to this url:

http://{hostname}/{the Site Collection}/_layouts/15/appinv.aspx

And paste your GUID. Some data should pop up.

AND finally you need a little XML in that textbox


<AppPermissionRequests>
 <AppPermissionRequest 
      Scope="http://sharepoint/content/sitecollection" 
      Right="FullControl" />
</AppPermissionRequests>

Save and you should be all set. If Publish WF again fire error, just close and open SPD again.

6. Run on Item Created (for the example), enjoy

...


7. Error Handling

If you get some errors, trying to understand what was the problem can be quite tough.

1st thing will be to log the ResponseCode to the WF history list. But then we just see "Bad Request". What can be the problem?

We must use the "Get an Item from a Dictionary" step 3 times:
1. Get "error" from ResponseBody into a Dictionary.
2. Get "message" from "error"'s Dictionary into a Dictionary.
3. Get "value" from "message"'s Dictionary into a String.
That you can finally log.






Comments

Post a Comment

Popular posts from this blog

OverTheWire[.com] Natas Walkthrough - JUST HINT, NO SPOILERS

SOLVED The item could not be indexed successfully because the item failed in the indexing subsystem

Asp.Net Ending Response options, Response.End() vs CompleteRequest()