TimeSheet.QueueReviewTimesheet 方法
从Submittted到Acceptable或Approved,或从Acceptable到Approved,具体取决于当前用户的权限和指定的操作,请更改指定的时间表的状态。
命名空间: WebSvcTimeSheet
程序集: ProjectServerServices(位于 ProjectServerServices.dll 中)
语法
声明
<SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/TimeSheet/QueueReviewTimesheet", RequestNamespace := "https://schemas.microsoft.com/office/project/server/webservices/TimeSheet/", _
ResponseNamespace := "https://schemas.microsoft.com/office/project/server/webservices/TimeSheet/", _
Use := SoapBindingUse.Literal, ParameterStyle := SoapParameterStyle.Wrapped)> _
Public Sub QueueReviewTimesheet ( _
jobUID As Guid, _
tsUID As Guid, _
nextApproverUID As Guid, _
comment As String, _
action As Action _
)
用法
Dim instance As TimeSheet
Dim jobUID As Guid
Dim tsUID As Guid
Dim nextApproverUID As Guid
Dim comment As String
Dim action As Action
instance.QueueReviewTimesheet(jobUID, _
tsUID, nextApproverUID, comment, _
action)
[SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/TimeSheet/QueueReviewTimesheet", RequestNamespace = "https://schemas.microsoft.com/office/project/server/webservices/TimeSheet/",
ResponseNamespace = "https://schemas.microsoft.com/office/project/server/webservices/TimeSheet/",
Use = SoapBindingUse.Literal, ParameterStyle = SoapParameterStyle.Wrapped)]
public void QueueReviewTimesheet(
Guid jobUID,
Guid tsUID,
Guid nextApproverUID,
string comment,
Action action
)
参数
jobUID
类型:System.Guid队列作业的唯一 ID。
tsUID
类型:System.Guid时间表的唯一 ID。
nextApproverUID
类型:System.Guid下一个时间表审批者的唯一 ID。
comment
类型:System.String要随操作的消息。
action
类型:WebSvcTimeSheet.ActionAction对象,指示下一个时间表的状态。
备注
通过 Project Server 时间表队列异步处理QueueReviewTimesheet方法。
此方法将提交到QueueSystem对象的作业。作业的CorrelationGUID属性等于TS_UID属性的值。
Project Server 权限
权限 |
说明 |
---|---|
非标准 |
当前用户是时间表管理者。 |
允许用户接受以供审批的时间表。仅适用于当前用户不是时间表管理者。全局权限。 |
示例
下面的代码示例创建空白时间表、 添加管理行、 准备行、 将其保存到数据库,并将其提交。然后,本示例审阅时间表,并批准其。
备注
您可能需要删除旧的时间表或不时间表示例资源没有打开期间是否创建时间段。
For critical information about running this code sample, see Project 2013 中基于 ASMX 的代码示例的先决条件.
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Data;
using System.Web.Services.Protocols;
using System.Threading;
using PSLibrary = Microsoft.Office.Project.Server.Library;
namespace Microsoft.SDK.Project.Samples.QueueReviewTimesheet
{
class Program
{
[STAThread]
static void Main()
{
try
{
#region Setup
const string PROJECT_SERVER_URI = "http:// ServerName/ProjectServerName/"; // <<--Change to be the name of your server running Project Server and the name of your directory.
const string TIMESHEET_SERVICE_PATH = "_vti_bin/psi/timesheet.asmx";
const string RESOURCE_SERVICE_PATH = "_vti_bin/psi/resource.asmx";
const string ADMIN_SERVICE_PATH = "_vti_bin/psi/admin.asmx";
const string QUEUESYSTEM_SERVICE_PATH = "_vti_bin/psi/queuesystem.asmx";
TimeSheetWebSvc.TimesheetDataSet timesheetDs;
// Set up the services.
TimeSheetWebSvc.TimeSheet timeSheetSvc = new TimeSheetWebSvc.TimeSheet();
timeSheetSvc.UseDefaultCredentials = true;
timeSheetSvc.Url = PROJECT_SERVER_URI + TIMESHEET_SERVICE_PATH;
CodeSample_TimeSheetUtilities timeSheetUtils = new CodeSample_TimeSheetUtilities(timeSheetSvc);
ResourceWebSvc.Resource resourceSvc = new ResourceWebSvc.Resource();
resourceSvc.Url = PROJECT_SERVER_URI + RESOURCE_SERVICE_PATH;
resourceSvc.UseDefaultCredentials = true;
CodeSample_ResourceUtilities resourceUtils = new CodeSample_ResourceUtilities(resourceSvc);
AdminWebSvc.Admin adminSvc = new AdminWebSvc.Admin();
adminSvc.Url = PROJECT_SERVER_URI + ADMIN_SERVICE_PATH;
adminSvc.UseDefaultCredentials = true;
QueueSystemWebSvc.QueueSystem q = new QueueSystemWebSvc.QueueSystem();
q.Url = PROJECT_SERVER_URI + QUEUESYSTEM_SERVICE_PATH;
q.UseDefaultCredentials = true;
AdminWebSvc.TimesheetLineClassDataSet tsLineClassDs = adminSvc.ReadLineClasses(AdminWebSvc.LineClassType.AllNonProject, AdminWebSvc.LineClassState.Enabled);
#endregion
#region Setup a timesheet with no lines
Guid sampleResourceUid = resourceUtils.EnsureLertchai();
AdminWebSvc.TimePeriodDataSet timePeriodDs = adminSvc.ReadPeriods(AdminWebSvc.PeriodState.Open);
Guid periodUid = timeSheetUtils.FindFirstEmptyPeriod(sampleResourceUid, timePeriodDs);
Guid timeSheetUid = timeSheetUtils.CreateEmptyTimeSheetFor(sampleResourceUid, resourceUtils.myUid, periodUid);
timesheetDs = timeSheetSvc.ReadTimesheet(timeSheetUid);
TimeSheetWebSvc.TimesheetDataSet.LinesRow line = timesheetDs.Lines.NewLinesRow();
line.TS_UID = timeSheetUid;
line.TS_LINE_UID = Guid.NewGuid();
line.TS_LINE_CLASS_UID = tsLineClassDs.LineClasses[0].TS_LINE_CLASS_UID;
line.TS_LINE_COMMENT = "Added by code sample.";
line.TS_LINE_STATUS = (byte)PSLibrary.TimesheetEnum.LineStatus.NotApplicable;
line.TS_LINE_VALIDATION_TYPE = (byte)PSLibrary.TimesheetEnum.ValidationType.Unverified;
line.TS_LINE_CACHED_ASSIGN_NAME = tsLineClassDs.LineClasses[0].TS_LINE_CLASS_DESC;
timesheetDs.Lines.AddLinesRow(line);
Console.WriteLine("Prepare the timesheet...");
timeSheetSvc.PrepareTimesheetLine(timeSheetUid, ref timesheetDs, new Guid[] { line.TS_LINE_UID });
Console.WriteLine("Save the changes to the database...");
Guid jobUid = Guid.NewGuid();
timeSheetSvc.QueueUpdateTimesheet(jobUid, timeSheetUid, timesheetDs);
CodeSampleUtilities.WaitForQueue(q, jobUid);
jobUid = Guid.NewGuid();
timeSheetSvc.QueueSubmitTimesheet(jobUid, timeSheetUid,resourceUtils.myUid, "Submitted via code sample");
CodeSampleUtilities.WaitForQueue(q, jobUid);
#endregion
#region Review the timesheet
Console.WriteLine("Review and approve the timesheet");
jobUid = Guid.NewGuid();
timeSheetSvc.QueueReviewTimesheet(jobUid, timeSheetUid, Guid.Empty, "Approved via code sample", TimeSheetWebSvc.Action.Approve);
CodeSampleUtilities.WaitForQueue(q, jobUid);
timesheetDs = timeSheetSvc.ReadTimesheet(timeSheetUid);
CodeSampleUtilities.WriteTablesFormated("After approval:", timesheetDs.Tables);
#endregion
}
catch (SoapException ex)
{
ExceptionHandlers.HandleSoapException(ex);
}
catch (WebException ex)
{
ExceptionHandlers.HandleWebException(ex);
}
catch (Exception ex)
{
ExceptionHandlers.HandleException(ex);
}
finally
{
ExceptionHandlers.ResetConsole();
}
}
}
class ExceptionHandlers
{
public static void HandleSoapException(SoapException ex)
{
PSLibrary.PSClientError error = new PSLibrary.PSClientError(ex);
PSLibrary.PSErrorInfo[] errors = error.GetAllErrors();
string errMess = "==============================\r\nError: \r\n";
for (int i = 0; i < errors.Length; i++)
{
errMess += "\n" + ex.Message.ToString() + "\r\n";
errMess += "".PadRight(30, '=') + "\r\nPSCLientError Output:\r\n \r\n";
errMess += errors[i].ErrId.ToString() + "\n";
for (int j = 0; j < errors[i].ErrorAttributes.Length; j++)
{
errMess += "\r\n\t" + errors[i].ErrorAttributeNames()[j] + ": "
+ errors[i].ErrorAttributes[j];
}
errMess += "\r\n".PadRight(30, '=');
}
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(errMess);
}
public static void HandleWebException(WebException ex)
{
string errMess = ex.Message.ToString() +
"\n\nLog on, or check the Project Server Queuing Service";
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Error: " + errMess);
}
public static void HandleException(Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Error: " + ex.Message);
}
public static void ResetConsole()
{
Console.ResetColor();
Console.WriteLine("\r\n\r\nPress any key...");
Console.ReadKey();
}
}
class CodeSampleUtilities
{
// Write all contents of a table collection to the console.
public static void WriteTablesToConsole(System.Data.DataTableCollection theTables)
{
Console.ForegroundColor = ConsoleColor.DarkGreen;
foreach (System.Data.DataTable table in theTables)
{
int[] columnWidths = new int[table.Columns.Count];
int tableWidth = 0;
string dataString;
Console.WriteLine("Table: " + table.TableName);
// Write out the column names and get their spacing.
StringBuilder tableRow = new StringBuilder();
for (int i = 0; i < table.Columns.Count; i++)
{
columnWidths[i] = GetColumnWidth(table.Columns[i]);
tableRow.Append(table.Columns[i].ColumnName.PadRight(columnWidths[i]));
tableWidth += columnWidths[i];
}
// Add a space so it will not wrap.
tableWidth += 1;
// Make the console as wide as the widest table.
Console.BufferWidth = (Console.BufferWidth > tableWidth ? Console.BufferWidth : tableWidth);
tableRow.Append("\r\n");
Console.Write(tableRow.ToString());
// Write out the data.
foreach (DataRow row in table.Rows)
{
tableRow = new StringBuilder();
for (int i = 0; i < table.Columns.Count; i++)
{
dataString = row[i].ToString();
// Truncate output if it is wider than
// the desired column width.
if (dataString.Length >= columnWidths[i])
{
dataString = dataString.Substring(0, columnWidths[i] - 1);
}
// Add the output to the stringbuilder and pad right to fill
// up to the column width.
tableRow.Append(dataString.PadRight(columnWidths[i]));
}
tableRow.Append("\r\n");
Console.Write(tableRow.ToString());
}
Console.Write("\r\n".PadLeft(tableWidth, '-'));
}
Console.ResetColor();
}
// A helper function for WriteTablesToConsole.
private static int GetColumnWidth(DataColumn column)
{
// Note: Might not handle byte[]data types well.
const int MAX_COL_WIDTH = 40;
int dataWidth = 0;
// Return 12 for numbers, 30 for dates, and string width for strings.
switch (column.DataType.UnderlyingSystemType.ToString())
{
case "System.Boolean":
case "System.Byte":
case "System.Byte[]":
case "System.Char":
case "System.Decimal":
case "System.Double":
case "System.Int16":
case "System.Int32":
case "System.Int64":
case "System.SByte":
case "System.Single":
case "System.UInt16":
case "System.UInt32":
case "System.UInt64":
dataWidth = 12;
break;
case "System.DateTime":
case "System.TimeSpan":
dataWidth = 30;
break;
case "System.Guid":
dataWidth = 37;
break;
case "System.String":
// If it has a maxlength, use it.
if (column.MaxLength > 0)
{
dataWidth = column.MaxLength;
}
else
{
// Otherwise, use the max col width.
dataWidth = MAX_COL_WIDTH;
}
break;
default:
dataWidth = column.ColumnName.Length;
break;
}
// Truncate if over the maxlength.
if (dataWidth > MAX_COL_WIDTH)
{
dataWidth = MAX_COL_WIDTH;
}
// Always be at least as wide as the colum name.
return (column.ColumnName.Length > (dataWidth) ? column.ColumnName.Length + 1 : dataWidth);
}
public static void WriteTablesFormated(string Title, System.Data.DataTableCollection theTables)
{
WriteSeparator();
Console.WriteLine(Title);
CodeSampleUtilities.WriteTablesToConsole(theTables);
}
public static void WriteSeparator()
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine("".PadRight(Console.BufferWidth, '='));
Console.ResetColor();
}
// Wait for the job to finish.
// Outputs job status to the console.
static public void WaitForQueue(QueueSystemWebSvc.QueueSystem q, Guid jobId)
{
QueueSystemWebSvc.JobState jobState;
const int QUEUE_WAIT_TIME = 1; // One second
bool jobDone = false;
string xmlError = string.Empty;
int wait = 0;
//Wait for the project to get through the queue.
// Get the estimated wait time in seconds.
wait = q.GetJobWaitTime(jobId);
// Wait for it.
Console.Write("Waiting on queue. Estimate: {0} seconds.\r\n ", wait);
// Wait until it is finished.
do
{
// Get the job state.
jobState = q.GetJobCompletionState(jobId, out xmlError);
if (jobState == QueueSystemWebSvc.JobState.Success)
{
jobDone = true;
}
else
{
if (jobState == QueueSystemWebSvc.JobState.Unknown
|| jobState == QueueSystemWebSvc.JobState.Failed
|| jobState == QueueSystemWebSvc.JobState.FailedNotBlocking
|| jobState == QueueSystemWebSvc.JobState.CorrelationBlocked
|| jobState == QueueSystemWebSvc.JobState.Canceled)
{
// If the job failed, error out.
throw (new ApplicationException("Queue request " + jobState + " for Job ID " + jobId + ".\r\n" + xmlError));
}
else
{
//Console.WriteLine("Job State: " + jobState + " for Job ID: " + jobId);
Console.Write("~");
Thread.Sleep(QUEUE_WAIT_TIME * 1000);
}
}
}
while (!jobDone);
Console.Write("\r\n");
}
}
class CodeSample_TimeSheetUtilities
{
TimeSheetWebSvc.TimeSheet timeSheetSvc;
public CodeSample_TimeSheetUtilities(TimeSheetWebSvc.TimeSheet theTimeSheetSvc)
{
timeSheetSvc = theTimeSheetSvc;
}
public Guid CreateEmptyTimeSheetFor(Guid resourceGuid, Guid mgrUid, Guid periodUid)
{
TimeSheetWebSvc.TimesheetDataSet timesheetDs = new TimeSheetWebSvc.TimesheetDataSet();
TimeSheetWebSvc.TimesheetDataSet.HeadersRow headersRow = timesheetDs.Headers.NewHeadersRow();
headersRow.RES_UID = resourceGuid;
headersRow.TS_UID = Guid.NewGuid();
headersRow.WPRD_UID = periodUid;
headersRow.TS_CREATOR_RES_UID = mgrUid;
headersRow.TS_NAME = "Timesheet ";
headersRow.TS_COMMENTS = "Timesheet for code sample";
headersRow.TS_ENTRY_MODE_ENUM = (byte)PSLibrary.TimesheetEnum.EntryMode.Weekly;
timesheetDs.Headers.AddHeadersRow(headersRow);
// Create the timesheet with the default line types that are specified by the admin.
timeSheetSvc.CreateTimesheet(timesheetDs, TimeSheetWebSvc.PreloadType.None);
return headersRow.TS_UID;
}
public Guid FindFirstEmptyPeriod(Guid resUid, AdminWebSvc.TimePeriodDataSet timePeriodDs)
{
TimeSheetWebSvc.TimesheetDataSet timeSheetDs;
for (int i = 0; i < timePeriodDs.TimePeriods.Count; i++)
{
timeSheetDs = timeSheetSvc.ReadTimesheetByPeriod(resUid, timePeriodDs.TimePeriods[i].WPRD_UID, TimeSheetWebSvc.Navigation.Current);
if (timeSheetDs.Headers.Count == 0)
{
return timePeriodDs.TimePeriods[i].WPRD_UID;
}
}
return Guid.Empty;
}
}
class CodeSample_ResourceUtilities
{
private ResourceWebSvc.Resource m_resourceSvc;
private Guid m_MyUid;
private Guid sampleResource = Guid.Empty;
public CodeSample_ResourceUtilities(ResourceWebSvc.Resource theResourceSvc)
{
m_resourceSvc = theResourceSvc;
m_MyUid = resourceSvc.GetCurrentUserUid();
}
public Guid myUid
{
get { return m_MyUid; }
}
public ResourceWebSvc.Resource resourceSvc
{
get { return m_resourceSvc; }
}
public Guid EnsureLertchai()
{
return EnsureSampleResource("Lertchai Treetawatchaiwong", "LT");
}
public Guid EnsureSampleResource(string name, string inits)
{
Guid resGuid = GetResourceGuid(name);
if (resGuid == Guid.Empty)
{
resGuid = this.CreateResource(name, inits, myUid);
}
return resGuid;
}
public Guid GetResourceGuid(string resourceName)
{
ResourceWebSvc.ResourceDataSet resourceDs = new ResourceWebSvc.ResourceDataSet();
PSLibrary.Filter resourceFilter = new Microsoft.Office.Project.Server.Library.Filter();
resourceFilter.FilterTableName = resourceDs.Resources.TableName;
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.Resources.TableName, resourceDs.Resources.RES_UIDColumn.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));
resourceFilter.Fields.Add(new PSLibrary.Filter.Field(resourceDs.Resources.TableName, resourceDs.Resources.RES_NAMEColumn.ColumnName, PSLibrary.Filter.SortOrderTypeEnum.None));
PSLibrary.Filter.FieldOperator existingResource = new PSLibrary.Filter.FieldOperator(PSLibrary.Filter.FieldOperationType.Equal, resourceDs.Resources.RES_NAMEColumn.ColumnName, resourceName);
resourceFilter.Criteria = existingResource;
resourceDs = resourceSvc.ReadResources(resourceFilter.GetXml(), false);
if (resourceDs.Resources.Count >= 1)
{
return resourceDs.Resources[0].RES_UID;
}
else
{
return Guid.Empty;
}
}
private Guid CreateResource(string resourceName, string initials, Guid timesheetMgr)
{
ResourceWebSvc.ResourceDataSet resourceDs = new ResourceWebSvc.ResourceDataSet();
ResourceWebSvc.ResourceDataSet.ResourcesRow resourceRow = resourceDs.Resources.NewResourcesRow();
resourceRow.RES_UID = Guid.NewGuid();
resourceRow.RES_NAME = resourceName;
resourceRow.RES_INITIALS = initials;
resourceRow.RES_TYPE = (int)PSLibrary.Resource.Type.WorkResource;
resourceRow.RES_TIMESHEET_MGR_UID = timesheetMgr;
resourceDs.Resources.AddResourcesRow(resourceRow);
resourceSvc.CreateResources(resourceDs, false, true);
return resourceRow.RES_UID;
}
}
}