Add multiple Calendar Exceptions to Project server using PSI

Recently I had to write a Project Server gateway (a class library) that interacts with Project server site using Project server webservices. In this case, I had to copy all the leave details from some old system to Project Server 2010.

The only challenge that I faced was to filter and fill the Resources dataset only with list of  selected resources while adding their Calendar Exceptions(or leave details). To begin with lets first create an Entity class ‘CalendarException’ which will have all the leave details including the ResourceId.

public class CalendarException
{
public Guid ResourceId
{ get; set; }

public DateTime Start
{  set;  get; }

public DateTime Finish
{ set; get;  }

public string Name
{ get; set; }
}

 

Before adding calendar exceptions, the next step is to write a method that will fill the ‘Resources’ dataset only with the resources whose leave details are to be added in Project Server.

using PSLibrary = Microsoft.Office.Project.Server.Library;
private PSLibrary.Filter GetResourceFilter(Guid[] resources)
{
ResourceWS.ResourceDataSet resourceDs = new ResourceWS.ResourceDataSet();

PSLibrary.Filter resourceFilter = new PSLibrary.Filter();
resourceFilter.FilterTableName = resourceDs.Resources.TableName;
foreach (DataColumn column in resourceDs.Resources.Columns)
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.Resources.TableName, column.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));

foreach (DataColumn column in resourceDs.CalendarExceptions.Columns)
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.CalendarExceptions.TableName, column.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));

foreach (DataColumn column in resourceDs.ResourceRates.Columns)
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.ResourceRates.TableName, column.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));

foreach (DataColumn column in resourceDs.ResourceAvailabilities.Columns)
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.ResourceAvailabilities.TableName, column.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));

PSLibrary.Filter.IOperator[] fos = new PSLibrary.Filter.IOperator[resources.Length];
for (int i = 0; i < resources.Length; i++)
{
fos[i] = new PSLibrary.Filter.FieldOperator(PSLibrary.Filter.FieldOperationType.Equal, resourceDs.Resources.RES_UIDColumn.ColumnName, resources[i]);
}

PSLibrary.Filter.LogicalOperator lo = new Microsoft.Office.Project.Server.Library.Filter.LogicalOperator(PSLibrary.Filter.LogicalOperationType.Or, fos);

resourceFilter.Criteria = lo;
return resourceFilter;
}

Finally, add calendar exceptions. The method below will accept as an argument IEnumerable collection of all the calendar exceptions (or leave details) which are to be added.


public void AddCalendarExceptions(IEnumerable<CalendarExceptions> calendarExceptions)
{
Guid[] resourceIds = calendarExceptions.Select(resId => resId.ResourceId).ToArray();

PSLibrary.Filter resourceFilter = GetResourceFilter(resourceIds);
string filterXML = resourceFilter.GetXml();

ResourceWS.ResourceDataSet resourceDS = resourceWS.ReadResources(filterXML, false);
if (resourceDS != null)
{
try { resourceWS.CheckOutResources(resourceIds); }
catch (SoapException ex)
{
if (ex.Message.Contains(“CICOAlreadyCheckedOutToYou”))
{
resourceWS.CheckInResources(resourceIds, true);
resourceWS.CheckOutResources(resourceIds);
}
else
throw ex;
}

foreach (CalendarException calendarException in calendarExceptions)
FillCalendarExceptionRow(calendarException, resourceDS);

try
{
resourceWS.UpdateResources(resourceDS, false, true);
resourceWS.CheckInResources(resourceIds, true);
}
catch (SoapException ex)
{
if (ex.Message.Contains(“CICONotCheckedOut”)) { }
else throw ex;
}
}
}

Here is the complete code snippet –


public class CalendarException
{
public Guid ResourceId
{ get; set; }

public DateTime Start
{ set; get; }

public DateTime Finish
{ set; get; }

public string Name
{ get; set; }
}

using PSLibrary = Microsoft.Office.Project.Server.Library;
public class ResourceGateway
{
ResourceWS.Resource resourceWS;

public ResourceGateway(string serverUrl)
{
resourceWS = new ResourceWS.Resource();
resourceWS.Url = serverUrl + “/_vti_bin/PSI/Resource.asmx”;
resourceWS.Credentials = CredentialCache.DefaultCredentials;
}

public void AddCalendarExceptions(IEnumerablecalendarExceptions)
{
Guid[] resourceIds = calendarExceptions.Select(resId => resId.ResourceId).ToArray();

PSLibrary.Filter resourceFilter = GetResourceFilter(resourceIds);
string filterXML = resourceFilter.GetXml();

ResourceWS.ResourceDataSet resourceDS = resourceWS.ReadResources(filterXML, false);
if (resourceDS != null)
{
try { resourceWS.CheckOutResources(resourceIds); }
catch (SoapException ex)
{
if (ex.Message.Contains(“CICOAlreadyCheckedOutToYou”))
{
resourceWS.CheckInResources(resourceIds, true);
resourceWS.CheckOutResources(resourceIds);
}
else
throw ex;
}

foreach (CalendarException calendarException in calendarExceptions)
FillCalendarExceptionRow(calendarException, resourceDS);

try
{
resourceWS.UpdateResources(resourceDS, false, true);
resourceWS.CheckInResources(resourceIds, true);
}
catch (SoapException ex)
{
if (ex.Message.Contains(“CICONotCheckedOut”)) { }
else throw ex;
}
}
}

private PSLibrary.Filter GetResourceFilter(Guid[] resources)
{
ResourceWS.ResourceDataSet resourceDs = new ResourceWS.ResourceDataSet();

PSLibrary.Filter resourceFilter = new PSLibrary.Filter();
resourceFilter.FilterTableName = resourceDs.Resources.TableName;
foreach (DataColumn column in resourceDs.Resources.Columns)
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.Resources.TableName, column.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));

foreach (DataColumn column in resourceDs.CalendarExceptions.Columns)
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.CalendarExceptions.TableName, column.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));

foreach (DataColumn column in resourceDs.ResourceRates.Columns)
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.ResourceRates.TableName, column.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));

foreach (DataColumn column in resourceDs.ResourceAvailabilities.Columns)
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.ResourceAvailabilities.TableName, column.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));

PSLibrary.Filter.IOperator[] fos = new PSLibrary.Filter.IOperator[resources.Length];
for (int i = 0; i < resources.Length; i++)
{
fos[i] = new PSLibrary.Filter.FieldOperator(PSLibrary.Filter.FieldOperationType.Equal, resourceDs.Resources.RES_UIDColumn.ColumnName, resources[i]);
}

PSLibrary.Filter.LogicalOperator lo = new Microsoft.Office.Project.Server.Library.Filter.LogicalOperator(PSLibrary.Filter.LogicalOperationType.Or, fos);

resourceFilter.Criteria = lo;
return resourceFilter;
}
}

Trackbacks

Leave a Comment

Your email address will not be published. Required fields are marked *