After Copy BCWP Value changes in MSP’s Task Usage View

Last year had been busy, in fact very busy:) and it continues. during this time i have come across a problem in Project Server.

As usual our Sales team has promised customer 5 reports (part of their marketing plan where they do not check the requirements) without any requirement gathering. for which we landed in soup and it took hell lot of time for us to create those reports. in this one of the requirement was to show the earned value on monthly basis. which can be seen inside the MSP but unfortunately it is not available inside the Project Server database. and same has been confirmed by the MS during support call.  however customer being customer. they were adamant on getting this values from MSP, as it is crucial part in their reports. and customer being the construction domain earned value is their highest priority.

So, we went ahead and created the custom database. which takes the snapshot in monthly basis and stores the Project/ Task’s BCWP in my custom database. Now, there was another problem since this earned value is cumulative on month on month basis. this solution also did not served purpose. then we suggested that let’s introduce 2 custom fields

  1. Earned Value Current Month
  2. Earned Value Previous Month
  3. Net Earned Value (Calculated Field) = Earned Value Current Month – Earned Value Previous month + Cumulative EV for Last Month

after above custom field creation, we thought we have solved the purpose/ requirement of the customer. but no we faced another challenge where when we copy the BCWP from Task Usage view to Custom field. Somehow, that value gets change automatically. Which is again an Issue and not acceptable at all. then we found an article where MS has suggested to write a Macro which copies the BCWP and stores it inside the Custom Field. 

Now,Considering the pain i had to go through. and also i  i don’t want others to go through it. so below is how you create the form and update the custom Field. and form will look something like this:

Paste Earned Value

As you can see in above image After copy and Paste values change in Task Usage sheet. now without any further a due let’s just go with the code.

 

Private Sub btnCurrent_Click()
On Error GoTo A
    Call TimePhasedData(txtCurrStart.Value, txtCurrFinish.Value, "Earned Value Current Month")
    MsgBox "Previous Month EV value has been pasted successfully"
    Exit Sub
A:
MsgBox Err.Description
Exit Sub
End Sub
Sub TimePhasedData(s As Date, F As Date, CF_Name As String)
Dim T As Task
Dim tsv As TimeScaleValue
Dim tsvs As TimeScaleValues
   'Timephased for Task with a UniqueID of 1
   For Each T In ActiveProject.Tasks
        Set tsvs = T.TimeScaleData( _
           StartDate:=s, _
           EndDate:=F, _
           Type:=pjTaskTimescaledBCWP, _
           TimeScaleUnit:=pjTimescaleMonths, Count:=1)
        For Each tsv In tsvs
           Debug.Print "Task Name: " & T.Name & "Start: " & Format(tsv.StartDate, _
              "Long Date"), "BCWP: " & Val(tsv.Value) & "$"
         T.SetField (FieldNameToFieldConstant(CF_Name)), Val(tsv.Value)
        Next tsv
        Debug.Print 'Blank line
   Next T
End Sub

Update Project Custom Field in Project Online

Hi, It’s been many days i have written a blog. been busy working on some of the mobile projects outside Project Server. For a change.:)

Let’s do something which every Project Server Developer does, almost on daily basis. Updating the Project Custom fields.

As usual without wasting any time of yours and mine, straight to the code. Please leave a comment in case you require any clarification😉

Remember, updating the Project Level custom field is very easy in Project Online, you just have to append “custom_” with every UID of the custom field and it will straight up updates the custom field for you. which can be of any type other than Lookup (refer this to get the code value of the lookup table.

 private static void UpdateProjectCustomField()
        {
            DraftProject projCheckedOut = null;
            try
            {
                Dictionary<string, object> projDict = new Dictionary<string, object>();
                MsOnlineClaimsHelper claimsHelper = new MsOnlineClaimsHelper("https://abc/sites/pwa", "Email Add", "password");

                using (ProjectContext projContext = new ProjectContext("https://abc/sites/pwa"))
                {

                    projContext.ExecutingWebRequest += claimsHelper.clientContext_ExecutingWebRequest;

                    var PrjList = projContext.LoadQuery(projContext.Projects.Where(proj => proj.Name == "A1 Customer Demo"));
                    projContext.ExecuteQuery();
                    Guid pGuid = PrjList.First().Id;

                    PublishedProject proj2Edit = PrjList.First();
                    projCheckedOut = proj2Edit.CheckOut().IncludeCustomFields;
                    projContext.Load(projCheckedOut);
                    projContext.ExecuteQuery();

                    projDict = projCheckedOut.FieldValues;
                    if (!projDict.Contains(new KeyValuePair<string, object>("Custom_f80c56d8-b0ee-e211-b62d-00155d84f60d", "")))
                    {
                        projCheckedOut.FieldValues.Add("Custom_f80c56d8-b0ee-e211-b62d-00155d84f60d", "");
                    }
                    foreach (KeyValuePair<string, object> kvp in projDict)
                    {
                        try
                        {
                            Console.WriteLine("\tKey = {0}, Value = {1}", kvp.Key, kvp.Value.ToString());
                        }
                        catch { }
                    }

                    projCheckedOut.SetCustomFieldValue("Custom_da7594e7-e1f8-e211-85bd-00155d853508", "Technology Management");
                    QueueJob qJob = projCheckedOut.Publish(true);
                    JobState jobState = projContext.WaitForQueue(qJob, 70);
                }
            }
            catch (Exception ex)
            {

            }
        }

Update Resources using CSOM in Project Online

IT IS NOT POSSIBLE.:)

Recently, on one of the customer places we have been asked to do an Integration with their resource system. while doing so I was in a need of updating the Resource Level Customfield. Very Innocently i took an Approach of updating the Resource using the CSOM. but behold i could not find any method which will do so😦 then I logged a call with the microsoft support team and they have also come back saying that it is not possible, Forcibly i had to took the web services approach. And which took me to the unknown territory of authentication and authorization😦

So, Project Online does dual authentication which can be managed using the ClaimsHelper Class. but in our case client was using the Claim based authentication. so they used to have their own authentication page. and cause of that even ClaimsHelper class was not helping😦

Then i started working on storing cookies directly and passing them with the Web service’s CookieContainer. and then i was able to update the Resources.

First Let us refer to the Code shared by Microsoft on recording cookies and use the CSOM to fetch Web Title…

In the same solution Here, you will find the ReadCookies class which will read and then convert the same into the Cookie Collection using the following Code:

 private CookieCollection ExtractAuthCookiesFromUrl(string url)
        {
            Uri uriBase = new Uri(url);
            Uri uri = new Uri(uriBase, "/");
            // call WinInet.dll to get cookie.
            string stringCookie = CookieReader.GetCookie(uri.ToString());
            if (string.IsNullOrEmpty(stringCookie)) return null;
            stringCookie = stringCookie.Replace("; ", ",").Replace(";", ",");
            // use CookieContainer to parse the string cookie to CookieCollection
            CookieContainer cookieContainer = new CookieContainer();
            cookieContainer.SetCookies(uri, stringCookie);
            return cookieContainer.GetCookies(uri);
        }

Now, same will be used to pass into the Resource.asmx to update the Resource level custom fields.

Note:  How to get the cookies, Please use the the full solution where you found the ReadCookies Class. and debug the same to get the cookies as string which then can be pass into the above method which will be a cookie collections.

Hope this will help someone!!

Read Project & Task level custom field (Lookup)

Those who are working with project server will definately like to go with the CSOM, as It reduces lot of development effort for a developer in terms of the retrieving the custom field values of the project,task and resources. with CSOM it is very easy to fetch the custom field information by using the simple API which is FieldValues. By simply using such API CSOM will return the custom field information.

Now, this works perfectly ok when we are trying to fetch the normal custom field values. but when we need to get the custom field information, which has the lookup table is not worry hard but i would say little tricky.

Remember when we had to get the custom field values which had the lookup in the Project server 2007/2010. We need to get the project level custom fields and loop through to get the MD_PROP_ID and MD_PROP_UID and other details which will find the custom field name and Guid. then find the lookup values and match with the code values and lot of other stuff. 

Well, Here also we need to do few steps as mentioned below in order to fetch the information.

  1. First get all of the custom fields from the O365 and Loop through the same to get the InternalName of the Custom field
  2. Image
  3. This method will fetch the values from the Project Online for that lookup as we will only get the CODE_VALUE
  4. Now below is the code:
private static string CF_LookupValues(ProjectContext projContext, string CustomfieldName, string Value)
        {
            string str = "NA";
            try
            {
                MsOnlineClaimsHelper claimsHelper = new MsOnlineClaimsHelper(PWAUrl, UserName, Password);
                using (projContext = new ProjectContext(PWAUrl))
                {
                    projContext.ExecutingWebRequest += claimsHelper.clientContext_ExecutingWebRequest;
                    projContext.Load(projContext.Web);
                    projContext.ExecuteQuery();

                    var CustomFieldName = projContext.LoadQuery(projContext.CustomFields.Where(CF => CF.Name == CustomfieldName));
                    projContext.ExecuteQuery();

                    projContext.Load(CustomFieldName.First().LookupTable);
                    projContext.ExecuteQuery();

                    Guid LTuid = CustomFieldName.First().LookupTable.Id;

                    var LookupTableList = projContext.LoadQuery(projContext.LookupTables.Where(LT => LT.Id == LTuid));
                    projContext.ExecuteQuery();

                    projContext.Load(LookupTableList.First().Entries);
                    projContext.ExecuteQuery();
                    foreach (LookupEntry lutEntry in LookupTableList.First().Entries)
                    {
                        Guid Id = new Guid(Value.Remove(0, 6));
                        if (lutEntry.Id == Id)
                            str = lutEntry.FullValue.ToString();
                        //Console.WriteLine("\n\t{0}, SortIndex: {1}\n\tFullValue: {2}",lutEntry.Id, lutEntry.SortIndex.ToString("F0"), lutEntry.FullValue);
                    }
                }

            }
            catch (Exception ex)
            { }
            return str;
        }

Step by Step Gide to Office 2013 App – Development & Deployment (Shared Network Drive)

Finally, made an Office App. Here are the Steps through which we can create an Office App and deploy the same.

App Development

STEP 1



 

 

 

 

 

 

STEP 2

Choose which app you want to create

STEP 3

By default, it will create 2 solutions,

  • Manifest files
  • Web application


 

At this point if you will hit the F5, automatically it will open Project Professional for you and under the Project TAB, you will be able to see the App which we have created just now.

But this is not enough, if you wish to deploy this App and Run this without the F5, you need to publish these apps to the network drive.

Deploy this app on the Shared Network drive

STEP 1

  • Right click on the OfficeAppWeb2 and Click on the Publish Button

     

In the package location you can write the folder name, where you want to deploy this package. And later this same package will act as your Web Application. Which will host your web application inside the IIS.

 

 

Note:
Preferably it should be under the https, if you are using Azure for the same purpose. It will provide you the https

Now, Try to access the web Page from the browser first i.e. Home.html In case it gives you error while accessing the same. See to that you have Web Deploy 2.0,

And if still does not work then use,add and remove feature and see whether you have latest framework available or not (Generally this happens if you have installed .NET first and then Configured IIS)

Go to the control panel >> Add and Remove Feature and look under the Application Development feature.

STEP 2

Open the OfficeApp2 >> OfficeApp2Manifest >> OfficeApp2.xml

Now, Right click on the OfficeApp2 and
you will be prompted with the following screen:

 

 

Now, Click Finish and It will automatically open folder for you.

Copy the File from the OfficeAppManifests

And deploy the same inside some Network drive.

Add App Inside the Office 2013

  • Open the MSP
  • Go to the Project Options >> Trust Center >> Trust Center Settings
  • Select the Trusted App Catalogs

 


 

Once you click Ok, you need to restart the Project Professional 2013 again. Now we are all set to add an App inside the Project Professional

 

 

You will be able to see, Shared Folder Tab, Click and add the App

 

 

As you can see here, below is added app inside the Project Professional.

Hope this will help someone!! Feel free to leave comments in case it helps:)

Error occurred in deployment step ‘Install App for SharePoint’: Sideloading of apps is not enabled on this site.

Sometime back was creating an App that will publish all the projects in Project Online, While deploying the App. I was keep getting the following Error.

Error occurred in deployment step ‘Install App for SharePoint’: Sideloading of apps is not enabled on this site.

And then I found this post. By following the instruction I could deploy my apps very easily. though they do not recommend this script to be run on the production server.

when you will follow the above post, you will get result something like below:Image

Hope this will help someone.

Assign Project to Category in Project Server 2010

Once I had the requirement of Programatically assigning the Project to category. So First We need to find the Category GUID of the Category created inside the Project Server

                WbSvcSecurity.SecurityCategoriesDataSet CList = new WbSvcSecurity.SecurityCategoriesDataSet();
                Guid CategoryUid = new Guid();
                CList = sec.ReadCategoryList();
                for (int h = 0; h < CList.SecurityCategories.Count; h++)
                {
                    if (CList.SecurityCategories[h].WSEC_CAT_NAME == "Some CategoryName")
                    {
                        CategoryUid = CList.SecurityCategories[h].WSEC_CAT_UID;
                    }
                }

Now, Read the Category of that GUID and add the Project inside the Project

                CdS = sec.ReadCategory(CategoryUid);
                // Get a new objects row to put the created project into
                WbSvcSecurity.SecurityCategoriesDataSet.SecurityCategoryObjectsRow dsSecurityCategoryObjectsRow
                = CdS.SecurityCategoryObjects.NewSecurityCategoryObjectsRow();

                //Set the values
                Guid SECURITY_CATEGORY_OBJECT_TYPE_PROJECT = new Guid("1771B1C0-6E26-4FB3-A480-C798AB506E82");
                dsSecurityCategoryObjectsRow.WSEC_OBJ_TYPE_UID = SECURITY_CATEGORY_OBJECT_TYPE_PROJECT;
                dsSecurityCategoryObjectsRow.WSEC_CAT_UID = CategoryUid;
                dsSecurityCategoryObjectsRow.WSEC_OBJ_UID = new Guid("0e9a8ce3-2821-47c5-8ea4-ff602c499192");

                // Add the row to the dataset and then pass to SetCategories to update
                CdS.SecurityCategoryObjects.AddSecurityCategoryObjectsRow(dsSecurityCategoryObjectsRow);
                sec.SetCategories(CdS);

Scenario: When a Project Manager Creates a project and wants to assign the project in certain category using the project server custom field, where custom field is the list of available Categories. By choosing the Customfield value. We can programatically assign project to a category.

Hope this helps someone!!