TimeSheet.ApproveNonProjectTime 方法

指定的非项目时间项中,将状态更改从挂起批准或拒绝。

命名空间:  WebSvcTimeSheet
程序集:  ProjectServerServices(位于 ProjectServerServices.dll 中)

语法

声明
<SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/TimeSheet/ApproveNonProjectTime", 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 ApproveNonProjectTime ( _
    approvedTimesheetLines As Guid(), _
    rejectedTimesheetLines As Guid() _
)
用法
Dim instance As TimeSheet
Dim approvedTimesheetLines As Guid()
Dim rejectedTimesheetLines As Guid()

instance.ApproveNonProjectTime(approvedTimesheetLines, _
    rejectedTimesheetLines)
[SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/TimeSheet/ApproveNonProjectTime", 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 ApproveNonProjectTime(
    Guid[] approvedTimesheetLines,
    Guid[] rejectedTimesheetLines
)

参数

  • approvedTimesheetLines
    类型:[]

    TimesheetLines批准唯一标识符。

  • rejectedTimesheetLines
    类型:[]

    TimesheetLines拒绝唯一标识符。

备注

ApproveNonProjectTime作用于为其用户是时间表管理者的所有非项目时间表行。

此方法将提交到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.ApproveNonProjectTime
{
   class Program
   {
      [STAThread]
      static void Main()
      {
         try{
            #region Setup
            const string PROJECT_SERVER_URI = "https://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;

            #endregion
            #region Setup a timesheet with non-project time
            Guid sampleResourceUid = resourceUtils.EnsureLertchai();

            AdminWebSvc.TimePeriodDataSet timePeriodDs = adminSvc.ReadPeriods(AdminWebSvc.PeriodState.Open);

            Guid periodUid = timeSheetUtils.FindFirstEmptyPeriod(sampleResourceUid, timePeriodDs);
            Guid timeSheetUid = timeSheetUtils.CreateTimeSheetFor(sampleResourceUid, resourceUtils.myUid, periodUid);
            timesheetDs = timeSheetSvc.ReadTimesheet(timeSheetUid);

            // Find a line that requires approval.

            TimeSheetWebSvc.TimesheetDataSet.LinesRow[] approvalNeeded = (TimeSheetWebSvc.TimesheetDataSet.LinesRow[])timesheetDs.Lines.Select("TS_LINE_CLASS_NEED_APPROVAL = true");
            if (approvalNeeded.Length < 1)
            {
               throw(new ApplicationException("No lines requiring approval were found on the timesheet.\r\nChange your server settings so that one default admin type requires approval."));
            }

            TimeSheetWebSvc.TimesheetDataSet.ActualsRow actualsRow = timesheetDs.Actuals.NewActualsRow();
            AdminWebSvc.TimePeriodDataSet.TimePeriodsRow timePeriodsRow = timePeriodDs.TimePeriods.FindByWPRD_UID(periodUid);

            approvalNeeded[0].TS_LINE_COMMENT = "I really need a break.";
            actualsRow.TS_LINE_UID = approvalNeeded[0].TS_LINE_UID;
            actualsRow.TS_ACT_PLAN_VALUE =  1000 * 60 * 8;// 8 hours
            actualsRow.TS_ACT_NON_BILLABLE_VALUE = actualsRow.TS_ACT_PLAN_VALUE;
            actualsRow.TS_ACT_COMMENT = "Adding some time so it must be approved.";
            actualsRow.TS_ACT_FINISH_DATE = timePeriodsRow.WPRD_START_DATE.AddDays(1).AddTicks(-1);
            actualsRow.TS_ACT_START_DATE = timePeriodsRow.WPRD_START_DATE;
            timesheetDs.Actuals.AddActualsRow(actualsRow);

            actualsRow = timesheetDs.Actuals.NewActualsRow();
            actualsRow.TS_LINE_UID = approvalNeeded[0].TS_LINE_UID;
            actualsRow.TS_ACT_PLAN_VALUE = 1000 * 60 * 8;// 8 hours
            actualsRow.TS_ACT_NON_BILLABLE_VALUE = actualsRow.TS_ACT_PLAN_VALUE;
            actualsRow.TS_ACT_COMMENT = "Adding some time so it must be approved.";
            actualsRow.TS_ACT_FINISH_DATE = timePeriodsRow.WPRD_START_DATE.AddDays(2).AddTicks(-1);
            actualsRow.TS_ACT_START_DATE = timePeriodsRow.WPRD_START_DATE.AddDays(1);
            timesheetDs.Actuals.AddActualsRow(actualsRow);


            Guid jobUid = Guid.NewGuid();
            timeSheetSvc.QueueUpdateTimesheet(jobUid, timeSheetUid, timesheetDs);
            CodeSampleUtilities.WaitForQueue(q, jobUid);

            timesheetDs = timeSheetSvc.ReadTimesheet(timeSheetUid);

            CodeSampleUtilities.WriteTablesFormated("Timesheet DS data that needs approval", timesheetDs.Tables);
            #endregion
            #region Try submitting with out approval
            try
            {
               // This fails because the time must be approved.
               Console.WriteLine("Submit timesheet without approving administrative time.");
               jobUid=Guid.NewGuid();
               timeSheetSvc.QueueSubmitTimesheet(jobUid, timeSheetUid, resourceUtils.myUid, "This won't work the first time.");
               CodeSampleUtilities.WaitForQueue(q, jobUid);
            }
            catch (Exception ex)
            {
               Console.WriteLine("Submit failed because administrative time needed to be approved.");
               ExceptionHandlers.HandleException(ex);
               q.CancelJob(jobUid, true, true);
               Console.ResetColor();
            }
            #endregion
            #region Approve non-project time.

            Console.WriteLine("Approve the non-project type.");
            timeSheetSvc.ApproveNonProjectTime(new Guid[] { approvalNeeded[0].TS_LINE_UID }, null);
            #endregion
            #region Resubmit after approval
            // Now try the submission again...
            // This works because the administrative time was approved.
            Console.WriteLine("Try the submission again.");
            jobUid = Guid.NewGuid();
            timeSheetSvc.QueueSubmitTimesheet(jobUid, timeSheetUid, resourceUtils.myUid, "This will work.");
            CodeSampleUtilities.WaitForQueue(q, jobUid);

            timesheetDs = timeSheetSvc.ReadTimesheet(timeSheetUid);
            CodeSampleUtilities.WriteTablesFormated("Submission succeeded!", 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 that 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();
      }
      // 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 CreateTimeSheetFor(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.Default);

         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;
      }
   }
}

另请参阅

引用

TimeSheet 类

TimeSheet 成员

WebSvcTimeSheet 命名空间