none
Project Online REST API to add a task to project? RRS feed

  • Question

  • I want to add a task to a project form a workflow using the HTTP web service action.  I am able to check out, check in and publish the project but I have not been successful in adding a task to the project.

    What is the REST API to add a task to a project?

    I have not been able to find an example of this, only to references that don't explain entirely how to accomplish this nor show an example URL.

    Example, here are the REST APIs to check out, check in and publish a project


    POST http: //<sitecollection>.sharepoint.com/<site>/_api/ProjectServer/Projects('projectid')/checkout()

    POST http: //<sitecollection>.sharepoint.com/<site>/_api/ProjectServer/Projects('projectid')/Draft/publish(checkin)POST http: //<sitecollection>.sharepoint.com/<site>/_api/ProjectServer/Projects('projectid')/Draft/publish(true)

    Using the build dictionary with "Accept", "Content-Type" of string values “application/json;odata=verbose” as the response headers


    Thanks you for your help,


    John

    Monday, May 18, 2015 3:31 PM

All replies

  • John,

        This is a bit tricky using pure REST, but the call you are missing is the Update() on the Draft Project.

    Knowing exactly what to pass in your POST payload is the next step and to save time I would recommend you use the JSOM library PS.js to automate all of this behaviour as well as getting access to functions to monitor the queue progress.  There are some samples here.

    Regards,

       James.


    James Boman BSc. MCP:EAD -

    Monday, May 18, 2015 11:57 PM
  • Thank you James.

    I'm actually able to check out a project using the SPD workflow action Call HTTP web service, then update a field on the project using a built in workflow action and then update and publish the project using the Call HTTP web service action.

    The part I'm missing is adding a new task to the project.  From your suggestion on using PS.js, how do I do that in a SPD workflow?  I haven't been able to add a new task to the project in a SPD workflow. That is the part I'm not able to get working. 

    Thanks for your assistance,

    John

    Wednesday, May 20, 2015 11:47 AM
  • The part I'm missing is adding a new task to the project.  From your suggestion on using PS.js, how do I do that in a SPD workflow?    

    John,

       Sorry I misread the part about the workflow - so PS.js is not an option for you.

    Knowing how the JSOM object model works, I would take a look at the data received via the CheckOut method, which returns a draft project - alter the data and POST it back to the the Update method.  Finally check in and publish the project as you were doing.

    Good luck,

       James.



    James Boman BSc. MCP:EAD -

    Thursday, May 21, 2015 2:13 AM
  • I'm with John on this. I need REST calls for what I'm doing.

    All the posts I've found are a mixture of PowerShell, JSOM and C# which don't help.

    It seems impossible to find an end to end example of REST calls for simple Project processes.

    I'm working with Project Online and this is as far as I've gotten with REST calls for Tasks...

    function AddTaskToProjectREST(TaskToAdd) {
        $.ajax({
            url: _spPageContextInfo.webAbsoluteUrl + "/_api/ProjectServer/Projects('" + projectGUID + "')/Draft/Tasks/Add",
            type: "POST",
            headers: { "accept": "application/json;odata=verbose" },
            body: {
                "parameters":
                    {
                        "Id": TaskToAdd.GUID,
                        "Name": TaskToAdd.Title,
                        "Notes": TaskToAdd.Comment,
                        "Start": new Date().toISOString(),
                        "Duration": TaskToAdd.DurationInBillable,
                        "AddAfterId": TaskToAdd.PredeceessorGUID
                    }
            },
            success: function (data) {
                if (data.d.results) {
                    alert("Task added successfully");
                }
            },
            error: function (xhr) {
                alert(xhr.status + ': ' + xhr.statusText);
            }
        });
    }

    Does anyone have a simple example of all the REST calls required to:

    1. Get hold of a project
    2. Check it out
    3. Add tasks (with predecessors)
    4. Update the project
    5. Check it in
    6. Publish it
    Monday, January 16, 2017 10:57 PM
  • I know the frustration very well! The following is all JAVA code, but should be easily readable/convertible  if you don't know JAVA. The following is a class called "Communications.java" and contains all the code (to date) to check in/out, publish, get/set custom fields, and add projects and tasks. I sincerely hope that this helps those who were where I was a few weeks ago trying to get pure REST calls working with Project Center.

    Creating a project is now as simple as:

    Communications comms = new Communications(baseURL);
    String projectName = "<the project name>";
    String safeName = projectName.replaceAll("\\W", "_");
    comms.createProject(safeName,projectName,"<my ID>","<start date in yyyy-mm-dd>");

    To get a list of all projects:

    Communications comms = new Communications(baseURL);
    JSONObject data = comms.GetData("/_api/ProjectServer/Projects");
    

    Communications.java:

    package pwa;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.UUID;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.WinHttpClients;
    import org.apache.http.util.EntityUtils;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    /**
     *
     * @author bplotkin
     */
    public class Communications
    {
        private String formDigestValue = "";
        private final String baseURL;
        private Date digestTime;
        public String lastError;
        public Boolean hasError;
        private String GUID;
        private ArrayList<CustomField> customFields;
    
        private class CustomField
        {
            String Name;
            String InternalName;
    
            public CustomField(String Name, String InternalName)
            {
                this.Name = Name;
                this.InternalName = InternalName;
            }
        }
    
        public Communications(String baseURL)
        {
            this.baseURL = baseURL;
            hasError = false;
            GUID = "";
            customFields = null;
        }
    
        /**
         * Builds the CloseableHttpClient Used for NLTM authentication of either the
         * logged-in user or can be used to build a static NTLM authenticator
         *
         * @return
         */
        private CloseableHttpClient buildClient()
        {
    //        CredentialsProvider credentials = new BasicCredentialsProvider();
    //        credentials.setCredentials(AuthScope.ANY, new NTCredentials("<username>","<password>",baseURL,"<domain>"));
    //        return HttpClients.custom().setDefaultCredentialsProvider(credentials).build();
            return WinHttpClients.createDefault();
        }
    
        /**
         * Get the FormDigestValue to be used for X-RequestFormDigest
         *
         * @return the digest value
         * @throws UnsupportedEncodingException
         * @throws IOException
         * @throws JSONException
         */
        private String getFormDigestValue() throws UnsupportedEncodingException, IOException, JSONException
        {
            // if current form digest value was obtained less than 12 hours ago, use it
            if (!formDigestValue.isEmpty() && digestTime.getTime() < (digestTime.getTime() + 43200000))
            {
                return formDigestValue;
            }
            CloseableHttpClient httpclient = buildClient();
            HttpPost post = new HttpPost(baseURL + "/_api/contextinfo");
            post.setHeader("Accept", "application/json;odata=verbose");
            post.addHeader("Content-Type", "application/json");
            CloseableHttpResponse response = httpclient.execute(post);
            byte[] content = EntityUtils.toByteArray(response.getEntity());
            response.close();
            httpclient.close();
            String jsonString = new String(content, "UTF-8");
            JSONObject json = new JSONObject(jsonString);
            formDigestValue = json.getJSONObject("d").getJSONObject("GetContextWebInformation").getString("FormDigestValue");
            digestTime = new Date();
            return formDigestValue;
        }
    
        /**
         * Perform a GET operation
         *
         * @param URL the rest of the URL, including the leading /
         * @return JSONObject
         * @throws IOException
         * @throws JSONException
         */
        public JSONObject GetData(String URL) throws IOException, JSONException
        {
            hasError = false;
            CloseableHttpClient httpclient = buildClient();
            HttpGet get = new HttpGet(baseURL + URL);
            get.setHeader("Accept", "application/json;odata=verbose");
            CloseableHttpResponse response = httpclient.execute(get);
            String jsonData = EntityUtils.toString(response.getEntity());
            response.close();
            httpclient.close();
            JSONObject json = new JSONObject(jsonData);
            if (json.has("d"))
            {
                return json.getJSONObject("d");
            }
            hasError = true;
            lastError = "Returned JSON has no starting point";
            return null;
        }
    
        /**
         * Checkout a project
         *
         * @param projectID ID of project
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws java.io.IOException
         * @throws org.json.JSONException
         */
        public boolean checkoutProject(String projectID) throws IOException, JSONException
        {
            hasError = false;
            CloseableHttpClient httpclient = buildClient();
            String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
            JSONObject json = GetData(projURL + "/?$select=IsCheckedOut");
            if (json == null)
            {
                hasError = true;
                lastError = "Get checkout state of project failed";
                return false;
            }
            boolean isCheckedOut = json.getBoolean("IsCheckedOut");
            if (!isCheckedOut)
            {
                String digest = getFormDigestValue();
                String fullurl = baseURL + projURL + "/CheckOut";
                HttpPost post = new HttpPost(fullurl);
                post.setHeader("Accept", "application/json;odata=verbose");
                post.setHeader("Content-Type", "application/json;odata=verbose;charset=utf-8");
                post.setHeader("X-RequestDigest", digest);
                CloseableHttpResponse response = httpclient.execute(post);
                response.close();
                httpclient.close();
                return response.getStatusLine().getStatusCode() == 200;
            }
            else
            {
                hasError = true;
                lastError = "Project already checked out";
                return false;
            }
        }
    
        /**
         * Check in a project
         *
         * @param projectID ID of project
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws java.io.IOException
         * @throws java.io.UnsupportedEncodingException
         * @throws org.json.JSONException
         */
        public boolean checkinProject(String projectID) throws IOException, UnsupportedEncodingException, JSONException
        {
            hasError = false;
            CloseableHttpClient httpclient = buildClient();
            String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
            String digest = getFormDigestValue();
            String fullurl = baseURL + projURL + "/Draft/CheckIn";
            HttpPost post = new HttpPost(fullurl);
            post.setHeader("Accept", "application/json;odata=verbose");
            post.setHeader("Content-Type", "application/json;odata=verbose;charset=utf-8");
            post.setHeader("X-RequestDigest", digest);
            CloseableHttpResponse response = httpclient.execute(post);
            response.close();
            httpclient.close();
            if (response.getStatusLine().getStatusCode() == 200)
            {
                return true;
            }
            hasError = true;
            lastError = response.getStatusLine().getReasonPhrase();
            return false;
        }
    
        /**
         * Gets the value of a custom field
         *
         * @param projectID
         * @param fieldID
         * @return the value of the field (or "" if the field doesn't exist or an error occurred)
         * If error, see Communications.lastError for details
         * @throws IOException
         * @throws JSONException
         */
        public String getCustomField(String projectID, String fieldID) throws IOException, JSONException
        {
            hasError = false;
            String[] customField = fieldID.split("_");
            if (customField.length == 2)
            {
                // not really sure why I have to prepend the x005f, but it seems to work, so I'll leave it for
                // now. Will need to look at this again when I have time
                String cfield = customField[0] + "_" + "x005f_" + customField[1];
                System.out.println(getCustomField(projectID, cfield));
    
                JSONObject json = GetData("/_api/ProjectServer/Projects('" + projectID + "')/IncludeCustomFields");
                if (json != null && json.has(fieldID))
                {
                    return json.getString(fieldID);
                }
            }
            hasError = true;
            lastError = "Field not found";
            return "";
        }
    
        /**
         * private method to get custom fields - only called once if custom fields array is empty
         */
        private void getCustomFields()
        {
            customFields = new ArrayList<>();
            try
            {
                JSONObject json = GetData("/_api/ProjectServer/CustomFields");
                JSONArray results = json.getJSONArray("results");
                for (int i = 0; i < results.length(); i++)
                {
                    JSONObject obj = results.getJSONObject(i);
                    if (obj.has("Name") && obj.has("InternalName"))
                    {
                        customFields.add(new CustomField(obj.getString("Name"), obj.getString("InternalName")));
                    }
                }
            }
            catch (IOException | JSONException ex)
            {
            }
        }
    
        /**
         * Set the value of a custom field
         *
         * @param projectID The GUID of the project
         * @param field The field to set
         * @param Type Field type (Edm.String, Edm.Decimal, see
         * http://www.odata.org/documentation/odata-version-2-0/overview/)
         * @param value The value for the field
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws java.io.IOException
         * @throws org.json.JSONException
         */
        public boolean setCustomField(String projectID, String field, String Type, String value) throws IOException, JSONException
        {
            if (customFields == null)
            {
                getCustomFields();
            }
            for (CustomField cfield : customFields)
            {
                if (cfield.Name.equals(field))
                {
                    String internalName = cfield.InternalName;
                    JSONObject postData = new JSONObject();
                    JSONArray custom = new JSONArray();
                    postData.put("customFieldDictionary", custom);
                    JSONObject obj = new JSONObject();
                    obj.put("Key", internalName);
                    obj.put("Value", value);
                    obj.put("ValueType", Type);
                    custom.put(obj);
                    CloseableHttpClient httpclient = buildClient();
                    String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
                    String digest = getFormDigestValue();
                    String fullurl = baseURL + projURL + "/Draft/UpdateCustomFields";
                    HttpPost post = new HttpPost(fullurl);
                    post.setHeader("Accept", "application/json;odata=verbose");
                    post.setHeader("Content-Type", "application/json;odata=verbose");
                    post.setHeader("X-RequestDigest", digest);
                    post.setHeader("X-HTTP-Method-Override", "MERGE");
                    post.setEntity(new StringEntity(postData.toString(0)));
                    CloseableHttpResponse response = httpclient.execute(post);
                    response.close();
                    httpclient.close();
                    if (response.getStatusLine().getStatusCode() == 200)
                    {
                        return true;
                    }
                    hasError = true;
                    lastError = response.getStatusLine().getReasonPhrase();
                    return false;
                }
            }
            hasError = true;
            lastError = "Field not found";
            return false;
        }
    
        /**
         * Publish a project
         *
         * @param projectID the project ID
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws IOException
         */
        public boolean publishProject(String projectID) throws IOException
        {
            hasError = false;
            String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
            String fullurl = baseURL + projURL + "/Draft/publish(true)";
            CloseableHttpClient httpclient = buildClient();
            HttpPost post = new HttpPost(fullurl);
            post.setHeader("Accept", "application/json;odata=verbose");
            post.setHeader("Content-Type", "application/json;odata=verbose;charset=utf-8");
            post.setHeader("X-RequestDigest", formDigestValue);
            CloseableHttpResponse response = httpclient.execute(post);
            response.close();
            httpclient.close();
            if (response.getStatusLine().getStatusCode() == 200)
            {
                return true;
            }
            hasError = true;
            lastError = response.getStatusLine().getReasonPhrase();
            return false;
        }
    
        /**
         * Create a new project in Project Center
         *
         * @param Name Name of the project
         * @param description Description of the project
         * @param ID Common ID of the project
         * @param start Start date of project
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws JSONException
         * @throws UnsupportedEncodingException
         * @throws IOException
         */
        public boolean createProject(String Name, String description, String ID, String start) throws JSONException, UnsupportedEncodingException, IOException, InterruptedException
        {
            hasError = false;
            String fullurl = baseURL + "/_api/ProjectServer/Projects/Add";
            CloseableHttpClient httpclient = buildClient();
            HttpPost post = new HttpPost(fullurl);
            post.setHeader("Accept", "application/json;odata=verbose");
            post.setHeader("Content-Type", "application/json;odata=verbose;charset=utf-8");
            post.setHeader("X-RequestDigest", getFormDigestValue());
            JSONObject json = new JSONObject();
            JSONObject parms = new JSONObject();
            json.put("parameters", parms);
            UUID uuid = UUID.randomUUID();
            GUID = uuid.toString();
            parms.put("Id", uuid.toString());
            parms.put("Name", Name);
            parms.put("Description", description);
            parms.put("Start", start);
            post.setEntity(new StringEntity(json.toString(0)));
            CloseableHttpResponse response = httpclient.execute(post);
            response.close();
            httpclient.close();
            // checkout new project and store commonID in the custom field 'Common ID'
            if (response.getStatusLine().getStatusCode() == 200)
            {
                Thread.sleep(500);
                if (checkoutProject(uuid.toString()))
                {
                    if (!setCustomField(uuid.toString(), "Common ID", "Edm.String", ID))
                    {
                        System.err.println("Cannot set Common ID: " + lastError);
                        checkinProject(uuid.toString());
                    }
                    else
                    {
                        publishProject(uuid.toString());
                    }
                }
                return true;
            }
            hasError = true;
            lastError = response.getStatusLine().getReasonPhrase();
            return false;
        }
    
        /**
         * Get the GUID 
         * @return the last GUID generated (for both a project and a task)
         */
        public String getGUID()
        {
            return GUID;
        }
    
        /**
         * Add a task to a given project
         * @param projectID The GUID of the project
         * @param feature The text of the task
         * @param startDate The start date of the task
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws IOException
         * @throws UnsupportedEncodingException
         * @throws JSONException 
         */
        public boolean addTask(String projectID, String feature, String startDate) throws IOException, UnsupportedEncodingException, JSONException
        {
            JSONObject postData = new JSONObject();
            JSONObject parms = new JSONObject();
            UUID uuid = UUID.randomUUID();
            parms.put("Id", uuid.toString());
            parms.put("Name", feature);
            parms.put("Start", startDate);
            postData.put("parameters", parms);
            CloseableHttpClient httpclient = buildClient();
            String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
            String digest = getFormDigestValue();
            String fullurl = baseURL + projURL + "/Draft/Tasks/Add";
            HttpPost post = new HttpPost(fullurl);
            post.setHeader("Accept", "application/json;odata=verbose");
            post.setHeader("Content-Type", "application/json;odata=verbose");
            post.setHeader("X-RequestDigest", digest);
            post.setEntity(new StringEntity(postData.toString(0)));
            CloseableHttpResponse response = httpclient.execute(post);
            response.close();
            httpclient.close();
            if (response.getStatusLine().getStatusCode() == 200)
            {
                GUID = uuid.toString();
                return true;
            }
            GUID = "";
            hasError = true;
            lastError = response.getStatusLine().getReasonPhrase();
            return false;
        }
    }
    


    Thursday, October 19, 2017 8:34 PM
  • I know the frustration very well! The following is all JAVA code, but should be easily readable/convertible  if you don't know JAVA. The following is a class called "Communications.java" and contains all the code (to date) to check in/out, publish, get/set custom fields, and add projects and tasks. I sincerely hope that this helps those who were where I was a few weeks ago trying to get pure REST calls working with Project Center.

    Creating a project is now as simple as:

    Communications comms = new Communications(baseURL);
    String projectName = "<the project name>";
    String safeName = projectName.replaceAll("\\W", "_");
    comms.createProject(safeName,projectName,"<my ID>","<start date in yyyy-mm-dd>");

    To get a list of all projects:

    Communications comms = new Communications(baseURL);
    JSONObject data = comms.GetData("/_api/ProjectServer/Projects");

    Communications.java:

    package pwa;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.UUID;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.WinHttpClients;
    import org.apache.http.util.EntityUtils;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    /**
     *
     * @author bplotkin
     */
    public class Communications
    {
        private String formDigestValue = "";
        private final String baseURL;
        private Date digestTime;
        public String lastError;
        public Boolean hasError;
        private String GUID;
        private ArrayList<CustomField> customFields;
    
        private class CustomField
        {
            String Name;
            String InternalName;
    
            public CustomField(String Name, String InternalName)
            {
                this.Name = Name;
                this.InternalName = InternalName;
            }
        }
    
        public Communications(String baseURL)
        {
            this.baseURL = baseURL;
            hasError = false;
            GUID = "";
            customFields = null;
        }
    
        /**
         * Builds the CloseableHttpClient Used for NLTM authentication of either the
         * logged-in user or can be used to build a static NTLM authenticator
         *
         * @return
         */
        private CloseableHttpClient buildClient()
        {
    //        CredentialsProvider credentials = new BasicCredentialsProvider();
    //        credentials.setCredentials(AuthScope.ANY, new NTCredentials("<username>","<password>",baseURL,"<domain>"));
    //        return HttpClients.custom().setDefaultCredentialsProvider(credentials).build();
            return WinHttpClients.createDefault();
        }
    
        /**
         * Get the FormDigestValue to be used for X-RequestFormDigest
         *
         * @return the digest value
         * @throws UnsupportedEncodingException
         * @throws IOException
         * @throws JSONException
         */
        private String getFormDigestValue() throws UnsupportedEncodingException, IOException, JSONException
        {
            // if current form digest value was obtained less than 12 hours ago, use it
            if (!formDigestValue.isEmpty() && digestTime.getTime() < (digestTime.getTime() + 43200000))
            {
                return formDigestValue;
            }
            CloseableHttpClient httpclient = buildClient();
            HttpPost post = new HttpPost(baseURL + "/_api/contextinfo");
            post.setHeader("Accept", "application/json;odata=verbose");
            post.addHeader("Content-Type", "application/json");
            CloseableHttpResponse response = httpclient.execute(post);
            byte[] content = EntityUtils.toByteArray(response.getEntity());
            response.close();
            httpclient.close();
            String jsonString = new String(content, "UTF-8");
            JSONObject json = new JSONObject(jsonString);
            formDigestValue = json.getJSONObject("d").getJSONObject("GetContextWebInformation").getString("FormDigestValue");
            digestTime = new Date();
            return formDigestValue;
        }
    
        /**
         * Perform a GET operation
         *
         * @param URL the rest of the URL, including the leading /
         * @return JSONObject
         * @throws IOException
         * @throws JSONException
         */
        public JSONObject GetData(String URL) throws IOException, JSONException
        {
            hasError = false;
            CloseableHttpClient httpclient = buildClient();
            HttpGet get = new HttpGet(baseURL + URL);
            get.setHeader("Accept", "application/json;odata=verbose");
            CloseableHttpResponse response = httpclient.execute(get);
            String jsonData = EntityUtils.toString(response.getEntity());
            response.close();
            httpclient.close();
            JSONObject json = new JSONObject(jsonData);
            if (json.has("d"))
            {
                return json.getJSONObject("d");
            }
            hasError = true;
            lastError = "Returned JSON has no starting point";
            return null;
        }
    
        /**
         * Checkout a project
         *
         * @param projectID ID of project
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws java.io.IOException
         * @throws org.json.JSONException
         */
        public boolean checkoutProject(String projectID) throws IOException, JSONException
        {
            hasError = false;
            CloseableHttpClient httpclient = buildClient();
            String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
            JSONObject json = GetData(projURL + "/?$select=IsCheckedOut");
            if (json == null)
            {
                hasError = true;
                lastError = "Get checkout state of project failed";
                return false;
            }
            boolean isCheckedOut = json.getBoolean("IsCheckedOut");
            if (!isCheckedOut)
            {
                String digest = getFormDigestValue();
                String fullurl = baseURL + projURL + "/CheckOut";
                HttpPost post = new HttpPost(fullurl);
                post.setHeader("Accept", "application/json;odata=verbose");
                post.setHeader("Content-Type", "application/json;odata=verbose;charset=utf-8");
                post.setHeader("X-RequestDigest", digest);
                CloseableHttpResponse response = httpclient.execute(post);
                response.close();
                httpclient.close();
                return response.getStatusLine().getStatusCode() == 200;
            }
            else
            {
                hasError = true;
                lastError = "Project already checked out";
                return false;
            }
        }
    
        /**
         * Check in a project
         *
         * @param projectID ID of project
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws java.io.IOException
         * @throws java.io.UnsupportedEncodingException
         * @throws org.json.JSONException
         */
        public boolean checkinProject(String projectID) throws IOException, UnsupportedEncodingException, JSONException
        {
            hasError = false;
            CloseableHttpClient httpclient = buildClient();
            String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
            String digest = getFormDigestValue();
            String fullurl = baseURL + projURL + "/Draft/CheckIn";
            HttpPost post = new HttpPost(fullurl);
            post.setHeader("Accept", "application/json;odata=verbose");
            post.setHeader("Content-Type", "application/json;odata=verbose;charset=utf-8");
            post.setHeader("X-RequestDigest", digest);
            CloseableHttpResponse response = httpclient.execute(post);
            response.close();
            httpclient.close();
            if (response.getStatusLine().getStatusCode() == 200)
            {
                return true;
            }
            hasError = true;
            lastError = response.getStatusLine().getReasonPhrase();
            return false;
        }
    
        /**
         * Gets the value of a custom field
         *
         * @param projectID
         * @param fieldID
         * @return the value of the field (or "" if the field doesn't exist or an error occurred)
         * If error, see Communications.lastError for details
         * @throws IOException
         * @throws JSONException
         */
        public String getCustomField(String projectID, String fieldID) throws IOException, JSONException
        {
            hasError = false;
            String[] customField = fieldID.split("_");
            if (customField.length == 2)
            {
                // not really sure why I have to prepend the x005f, but it seems to work, so I'll leave it for
                // now. Will need to look at this again when I have time
                String cfield = customField[0] + "_" + "x005f_" + customField[1];
                System.out.println(getCustomField(projectID, cfield));
    
                JSONObject json = GetData("/_api/ProjectServer/Projects('" + projectID + "')/IncludeCustomFields");
                if (json != null && json.has(fieldID))
                {
                    return json.getString(fieldID);
                }
            }
            hasError = true;
            lastError = "Field not found";
            return "";
        }
    
        /**
         * private method to get custom fields - only called once if custom fields array is empty
         */
        private void getCustomFields()
        {
            customFields = new ArrayList<>();
            try
            {
                JSONObject json = GetData("/_api/ProjectServer/CustomFields");
                JSONArray results = json.getJSONArray("results");
                for (int i = 0; i < results.length(); i++)
                {
                    JSONObject obj = results.getJSONObject(i);
                    if (obj.has("Name") && obj.has("InternalName"))
                    {
                        customFields.add(new CustomField(obj.getString("Name"), obj.getString("InternalName")));
                    }
                }
            }
            catch (IOException | JSONException ex)
            {
            }
        }
    
        /**
         * Set the value of a custom field
         *
         * @param projectID The GUID of the project
         * @param field The field to set
         * @param Type Field type (Edm.String, Edm.Decimal, see
         * http://www.odata.org/documentation/odata-version-2-0/overview/)
         * @param value The value for the field
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws java.io.IOException
         * @throws org.json.JSONException
         */
        public boolean setCustomField(String projectID, String field, String Type, String value) throws IOException, JSONException
        {
            if (customFields == null)
            {
                getCustomFields();
            }
            for (CustomField cfield : customFields)
            {
                if (cfield.Name.equals(field))
                {
                    String internalName = cfield.InternalName;
                    JSONObject postData = new JSONObject();
                    JSONArray custom = new JSONArray();
                    postData.put("customFieldDictionary", custom);
                    JSONObject obj = new JSONObject();
                    obj.put("Key", internalName);
                    obj.put("Value", value);
                    obj.put("ValueType", Type);
                    custom.put(obj);
                    CloseableHttpClient httpclient = buildClient();
                    String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
                    String digest = getFormDigestValue();
                    String fullurl = baseURL + projURL + "/Draft/UpdateCustomFields";
                    HttpPost post = new HttpPost(fullurl);
                    post.setHeader("Accept", "application/json;odata=verbose");
                    post.setHeader("Content-Type", "application/json;odata=verbose");
                    post.setHeader("X-RequestDigest", digest);
                    post.setHeader("X-HTTP-Method-Override", "MERGE");
                    post.setEntity(new StringEntity(postData.toString(0)));
                    CloseableHttpResponse response = httpclient.execute(post);
                    response.close();
                    httpclient.close();
                    if (response.getStatusLine().getStatusCode() == 200)
                    {
                        return true;
                    }
                    hasError = true;
                    lastError = response.getStatusLine().getReasonPhrase();
                    return false;
                }
            }
            hasError = true;
            lastError = "Field not found";
            return false;
        }
    
        /**
         * Publish a project
         *
         * @param projectID the project ID
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws IOException
         */
        public boolean publishProject(String projectID) throws IOException
        {
            hasError = false;
            String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
            String fullurl = baseURL + projURL + "/Draft/publish(true)";
            CloseableHttpClient httpclient = buildClient();
            HttpPost post = new HttpPost(fullurl);
            post.setHeader("Accept", "application/json;odata=verbose");
            post.setHeader("Content-Type", "application/json;odata=verbose;charset=utf-8");
            post.setHeader("X-RequestDigest", formDigestValue);
            CloseableHttpResponse response = httpclient.execute(post);
            response.close();
            httpclient.close();
            if (response.getStatusLine().getStatusCode() == 200)
            {
                return true;
            }
            hasError = true;
            lastError = response.getStatusLine().getReasonPhrase();
            return false;
        }
    
        /**
         * Create a new project in Project Center
         *
         * @param Name Name of the project
         * @param description Description of the project
         * @param ID Common ID of the project
         * @param start Start date of project
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws JSONException
         * @throws UnsupportedEncodingException
         * @throws IOException
         */
        public boolean createProject(String Name, String description, String ID, String start) throws JSONException, UnsupportedEncodingException, IOException, InterruptedException
        {
            hasError = false;
            String fullurl = baseURL + "/_api/ProjectServer/Projects/Add";
            CloseableHttpClient httpclient = buildClient();
            HttpPost post = new HttpPost(fullurl);
            post.setHeader("Accept", "application/json;odata=verbose");
            post.setHeader("Content-Type", "application/json;odata=verbose;charset=utf-8");
            post.setHeader("X-RequestDigest", getFormDigestValue());
            JSONObject json = new JSONObject();
            JSONObject parms = new JSONObject();
            json.put("parameters", parms);
            UUID uuid = UUID.randomUUID();
            GUID = uuid.toString();
            parms.put("Id", uuid.toString());
            parms.put("Name", Name);
            parms.put("Description", description);
            parms.put("Start", start);
            post.setEntity(new StringEntity(json.toString(0)));
            CloseableHttpResponse response = httpclient.execute(post);
            response.close();
            httpclient.close();
            // checkout new project and store commonID in the custom field 'Common ID'
            if (response.getStatusLine().getStatusCode() == 200)
            {
                Thread.sleep(500);
                if (checkoutProject(uuid.toString()))
                {
                    if (!setCustomField(uuid.toString(), "Common ID", "Edm.String", ID))
                    {
                        System.err.println("Cannot set Common ID: " + lastError);
                        checkinProject(uuid.toString());
                    }
                    else
                    {
                        publishProject(uuid.toString());
                    }
                }
                return true;
            }
            hasError = true;
            lastError = response.getStatusLine().getReasonPhrase();
            return false;
        }
    
        /**
         * Get the GUID 
         * @return the last GUID generated (for both a project and a task)
         */
        public String getGUID()
        {
            return GUID;
        }
    
        /**
         * Add a task to a given project
         * @param projectID The GUID of the project
         * @param feature The text of the task
         * @param startDate The start date of the task
         * @return true/false on success (see Communications.lastError for details if failed)
         * @throws IOException
         * @throws UnsupportedEncodingException
         * @throws JSONException 
         */
        public boolean addTask(String projectID, String feature, String startDate) throws IOException, UnsupportedEncodingException, JSONException
        {
            JSONObject postData = new JSONObject();
            JSONObject parms = new JSONObject();
            UUID uuid = UUID.randomUUID();
            parms.put("Id", uuid.toString());
            parms.put("Name", feature);
            parms.put("Start", startDate);
            postData.put("parameters", parms);
            CloseableHttpClient httpclient = buildClient();
            String projURL = "/_api/ProjectServer/Projects('" + projectID + "')";
            String digest = getFormDigestValue();
            String fullurl = baseURL + projURL + "/Draft/Tasks/Add";
            HttpPost post = new HttpPost(fullurl);
            post.setHeader("Accept", "application/json;odata=verbose");
            post.setHeader("Content-Type", "application/json;odata=verbose");
            post.setHeader("X-RequestDigest", digest);
            post.setEntity(new StringEntity(postData.toString(0)));
            CloseableHttpResponse response = httpclient.execute(post);
            response.close();
            httpclient.close();
            if (response.getStatusLine().getStatusCode() == 200)
            {
                GUID = uuid.toString();
                return true;
            }
            GUID = "";
            hasError = true;
            lastError = response.getStatusLine().getReasonPhrase();
            return false;
        }
    }


    Thanks for the code. But, Are you able to do the following :

    1. Update the timephasedData for a particular Assignment.

    2. Read All Tasks, Assignments & its TimephasedData.

    3. Once the TimePhasedData is updated get the percentage completion of each tasks.

    Please share Java code fragments, if you already have the same. Otherwise please instruct me some good samples or documentations to start with.

    Thanks in Advance !

     
    Sunday, April 15, 2018 5:27 PM