Remove Work Items and carry forward work item to next week

Sep 3, 2008 at 6:46 PM
Hi -

How do we removed any work item from the timesheet it it was entered by mistake? Can be move all the work items that are added to a week to the next week? Please advice.

Thank You,
Prashant.
Nov 27, 2011 at 11:57 AM

I have the same problem and i couldn't solve it

could any one help me

 

Regards,

Rana.

Jan 2, 2012 at 2:49 AM

This was pretty involved and took a couple of days for me to work out some of the kinks.  Code in blue is what I added or modified to get this work.  Hopefully I extracted everything needed, but if not you can probably follow what I am doing.

First add this javascript to the explorer.aspx file :

function CheckTime(workItemId, fieldName)
 {  
     var metadataKey;
     var total = 0;
            var dayIndex=0;

     var answer=false;
 
     for (dayIndex=0;dayIndex<=6;dayIndex++)
     {
          metadataKey = workItemId + "_" + dayIndex + "_" + fieldName;
          total = total + convertFromTimeString(timeEntryMetadata[metadataKey].originalValue);
     }

     if (total > 0)
     {      
         var answer = confirm("This will delete timesheet values you have already saved.  Do you wish to proceed ?")  
         if (!answer)
         {
              alert("Removal Cancelled !");
         }  
     }
     else
     {
          answer=true;  
     }  
     return answer;
 }

Also add an OnItemCommand attribute to the dataGridContainer and an additional column in the explorer.aspx file

 .........
 <asp:DataGrid ID="timesheetDataGrid" runat="server" AutoGenerateColumns="False" Width="100%" HeaderStyle-HorizontalAlign="Center" OnItemCommand="timesheetDataGrid_ItemCommand" OnItemDataBound="dataGridItem_DataBound" ShowFooter="true"  CellPadding="3" ItemStyle-HorizontalAlign="Center" FooterStyle-HorizontalAlign="Center" BorderStyle="Solid" BorderWidth="1" BorderColor="#DDDDDD" EnableViewState="false">
      <
Columns>
      <asp:TemplateColumn >
                        <ItemTemplate>
                            <asp:ImageButton ID="RemoveTimeSheetItem" ImageUrl="../../../Resources/Images/remove-clause.png" runat="server" />
                        </ItemTemplate>   
                    </asp:TemplateColumn>  
                    <asp:TemplateColumn ItemStyle-HorizontalAlign="Left" FooterStyle-HorizontalAlign="Left">
   <HeaderTemplate>
       WorkItem
   </HeaderTemplate> .......

You also need to add code to the codebehind for the explorer page, so you will need to recompile the Stratman.Web.VSTS.dll   In there you want to modify the following methods

        protected void dataGridItem_DataBound(object sender, DataGridItemEventArgs e)
        {
            // If this is a normal row, add the row's allocations to the totals for each day
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                DataRowView row = (DataRowView)e.Item.DataItem;
                bool isTotalRow = (bool)row["isTotalRow"];

                ImageButton RemoveButton = (ImageButton)(e.Item.Cells[0].FindControl("RemoveTimeSheetItem"));

                if (!isTotalRow)
                {
                    for (int i = 0; i < 8; i++)
                        columnTotals[i] += (Decimal)row[i + 6];
                    RemoveButton.Visible = true;
                   
                    string fieldName = (string)row["fieldName"];
                    RemoveButton.Attributes["onclick"] = "return CheckTime(" + row["workItemId"] + ", " + "'" + fieldName + "')";
                    RemoveButton.CommandName = "Delete";
                    RemoveButton.CommandArgument = row["workItemId"].ToString() + "," + fieldName;
                }
                else
                {
                    RemoveButton.Visible = false;                   
                }
            }         

            // If this is a footer, write the day totals to the appropriate cell
            else if (e.Item.ItemType == ListItemType.Footer)
            {
               for (int i = 0; i < 7; i++)
                    e.Item.Cells[i + dataColumnStart].Text = "<span id=\"day" + i.ToString() + "Total\">" + ConvertToTimeString(columnTotals[i], true) + "</span>";
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
 ...........

            // Set the enabled/disabled switch for the completed and approved buttons based on if
            // the user is looking at their own timesheet and/or they're an administrator
            if (currentUserSid != openUserSid)
            {
                completedRadioButtonList.Enabled = false;
                timesheetDataGrid.Columns[0].Visible = false;
            }           

            if (!IsUserAdministrator(Request.LogonUserIdentity.Name))
                approvedRadioButtonList.Enabled = false;

 ...........

            // Set the column headers for the grid
            for (int i = 0; i < 7; i++)
            {
                DateTime currentDay = startOfWeek.AddDays(i);
                timesheetDataGrid.Columns[i + dataColumnStart].HeaderText = currentDay.ToString("ddd<br/>MM/dd");
            }
 ...........

         }

        protected override void OnPreRender(EventArgs e)
        {
............

            // Register variables containing the initial state of the completed and approved radio
            // buttons
            if (completedRadioButtonList.Items[0].Selected)
            {
                RegisterStartupScript(this, "completedInitialState", "var completedInitialState = '" + completedRadioButtonList.Items[0].Value + "';");
                timesheetDataGrid.Columns[0].Visible = false;
            }
............

         }         

And add the following field to the class :

        /// <summary> 
        /// Defines which column begins display of the day data
        /// </summary>
        protected int dataColumnStart = 2;

And then add the following methods :

        protected void timesheetDataGrid_ItemCommand(object source, DataGridCommandEventArgs e)
        {
            string command = e.CommandName;            
            switch(command)
            {
                case "Edit":
                     break;
                case "Update"
                    break;
                case "Delete":
                    string[] commandArgs = e.CommandArgument.ToString().Split(new char[] {','});
                    int workItemId = System.Convert.ToInt16(commandArgs[0]);
                    string fieldName = commandArgs[1].ToString();
                    DeleteWorkItem(workItemId, fieldName);
                    break;
                default:
                    break;
            }
        }

        private void DeleteWorkItem(int workItemId, string fieldName)
        {
            string sid = openUserSid;           

            TimesheetSettings settings = (TimesheetSettings)ConfigurationManager.GetSection("timesheetSettings");
           
            // Create a connection to the database
            SqlConnection databaseConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["TimesheetDatabase"].ConnectionString);
            SqlCommand command = null;

            databaseConnection.Open();

            // Get a list of the WorkItems in this weeks data
            Dictionary<int, string> thisWeekItems = GetWeekItems(sid, databaseConnection, startOfWeek);

            // If the workitem is contained in this weeks data perform further checking.
            if (thisWeekItems.ContainsKey(workItemId))
            {
                string remainingHoursFieldName = "Unknown";

                if (settings.UpdateWorkItemsFromTimesheet.Enabled)
                {
                    // Obtain the workitem from the WorkItemStore
                    WorkItemStore workItemStore = Connection.Store;               
                    WorkItem workItem = workItemStore.GetWorkItem(workItemId);
                   
                    // Get the field name for the remaining hours for this time type
                    foreach (TimeAmount amount in settings.TimeAmounts)
                    {
                        if (amount.CompletedHoursFieldName == fieldName)
                            remainingHoursFieldName = amount.RemainingHoursFieldName;
                    }

                    // Get the total number of hours to remove from the workitem field
                    decimal totalHours = GetTotalWeekItemHours(sid, databaseConnection, startOfWeek, workItemId, fieldName);
                   
                    // Add the entry's delta to the number of completed hours for this work
                    // item and subtract it from the remaining hours if the config settings
                    // indicate that we are to synchronize that data
                    if (settings.UpdateWorkItemsFromTimesheet.Enabled)
                    {
                        Decimal completedHours = Convert.ToDecimal(workItem.Fields[fieldName].Value) - totalHours;
                        Decimal remainingHours = Convert.ToDecimal(workItem.Fields[remainingHoursFieldName].Value) + totalHours;

                        completedHours = (completedHours < 0 ? 0 : completedHours);
                        remainingHours = (remainingHours < 0 ? 0 : remainingHours);

                        workItem.Fields[fieldName].Value = completedHours;
                        workItem.Fields[remainingHoursFieldName].Value = remainingHours;

                        workItem.Save();
                    }
                }
                    
                // Remove this entry from the TimeSheetEntry
                command = new SqlCommand("usp_DEL_WorkItemForWeek", databaseConnection);

                command.CommandType = CommandType.StoredProcedure;
                command.Parameters.Add(new SqlParameter("@sid", sid));
                command.Parameters.Add(new SqlParameter("@startOfWeek", startOfWeek));
                command.Parameters.Add(new SqlParameter("@workItemId", workItemId));
                command.Parameters.Add(new SqlParameter("@fieldName", fieldName));               

                command.ExecuteNonQuery();
            }

            // Rebind the grid to refresh the screen
            timesheetDataGrid.DataSource = "";
            GetTimesheetData(databaseConnection);

            databaseConnection.Close();           
        }

Lastly, add a usp_DEL_WorkItemForWeek stored procedure to the timesheet dataase which will delete the Timesheet Entry based upon the user sid, startOfWeek, workItemId, and fieldName.  

Jan 2, 2012 at 3:01 AM

And one other modification which is purely optional. 

In our environment we added fields to the tasks that would break out meetings, collaboration, development time, etc for each task.

I found that when I had added two time amount types to a timesheet for the same workitem I was unable to tell them apart from each other easily.  So I modified the workitem name to include the workitemType and the workItemID.  At the same time I made the task name a link that would open a separate window to the actual task.

        protected void timesheetRowHeader_DataBinding(object sender, EventArgs e)
        {
            Literal rowHeader = (Literal)sender;
            DataRowView row = (DataRowView)((DataGridItem)rowHeader.NamingContainer).DataItem;
            bool isTotalRow = (bool)row["isTotalRow"];
            bool hasSiblings = (bool)row["hasSiblings"];

            // If this is the aggregate row for a group of different time entries for a specific
            // work item or is the header for a work item that has only one type of time entered
            // for it, display a link/title for that work item
            if (isTotalRow || !hasSiblings)
                rowHeader.Text = row["workItemType"].ToString() + ": <a href=\"javascript:void(0);\" title=\"" + row["workItemId"].ToString() + "\" onclick=\"WindowHelpers.openWorkItemEditorWithId(" + row["workItemId"].ToString() + ")\">" + row["workItemTitle"].ToString() + "</a>";

            // Otherwise, this row is for a specific type of time for a work item that has multiple
            // types of time; we simply display the label for this time type
            else
                rowHeader.Text = "&nbsp;&nbsp;&nbsp;&nbsp;" + GetTimeAmountLabel(row["fieldName"].ToString());
        }