Project

General

Profile

Feature #35657 » 0001-Add-a-basic-and-incomplete-POC-implementation-of-tot.patch

Patch against trunk @ r21131 - Mischa The Evil, 2021-08-13 21:11

View differences:

app/helpers/issues_helper.rb
284 284
    s
285 285
  end
286 286

  
287
  def spent_time_ratio_details(issue)
288
    if issue.total_estimated_hours.present? && issue.total_estimated_hours > 0
289
      if issue.total_spent_time_ratio == issue.spent_time_ratio
290
        content_tag(
291
          :span,
292
          "#{issue.spent_time_ratio.to_s(:percentage, precision: 2)}",
293
          class: "spent-time-ratio-value"
294
        )
295
      else
296
        s = !issue.spent_time_ratio.nil? && (issue.spent_time_ratio > 0) ?
297
              content_tag(
298
                :span, 
299
                "#{issue.spent_time_ratio.to_s(:percentage, precision: 2)}",
300
                class: "spent-time-ratio-value"
301
              ) :
302
            ""
303
        label = l(:label_total)
304
        value = content_tag(
305
                  :span,
306
                  "#{issue.total_spent_time_ratio.to_s(:percentage, precision: 2)}",
307
                  class: "total-spent-time-ratio-value"
308
                )
309
        s += " ("
310
        s += label
311
        s += ": "
312
        s += value
313
        s += ")"
314
        s.html_safe
315
      end
316
    end
317
  end
318

  
287 319
  # Returns a link for adding a new subtask to the given issue
288 320
  def link_to_new_subtask(issue)
289 321
    link_to(l(:button_add), url_for_new_subtask(issue))
app/helpers/queries_helper.rb
273 273
        link_to_if(value > 0, format_hours(value), project_time_entries_path(item.project, :issue_id => "~#{item.id}"))
274 274
      when :attachments
275 275
        value.to_a.map {|a| format_object(a)}.join(" ").html_safe
276
      when :spent_time_ratio, :total_spent_time_ratio
277
        !value.nil? ? value.to_s(:percentage, precision: 2) : ''
276 278
      else
277 279
        format_object(value)
278 280
      end
app/models/issue.rb
952 952
    due_date.present? && (due_date < User.current.today) && !closed?
953 953
  end
954 954

  
955
  def overspent?
956
    spent_time_ratio.present? && spent_time_ratio > 100
957
  end
958

  
959
  def total_overspent?
960
    total_spent_time_ratio.present? && total_spent_time_ratio > 100
961
  end
962

  
955 963
  # Is the amount of work done less than it should for the due date
956 964
  def behind_schedule?
957 965
    return false if start_date.nil? || due_date.nil?
......
1146 1154
    end
1147 1155
  end
1148 1156

  
1157
  def spent_time_ratio
1158
    if (estimated_hours.present? && estimated_hours > 0)
1159
      if (spent_hours.present? && spent_hours == 0)
1160
        0.to_f.round(2)
1161
      elsif (spent_hours.present? && spent_hours > 0)
1162
        spent_time_ratio = spent_hours.to_f / estimated_hours.to_f * 100.0
1163
        spent_time_ratio.round(2)
1164
      end
1165
    end
1166
  end
1167

  
1168
  def total_spent_time_ratio
1169
    if (total_estimated_hours.present? && total_estimated_hours > 0)
1170
      if (total_spent_hours.present? && total_spent_hours == 0)
1171
        0.to_f.round(2)
1172
      elsif (total_spent_hours.present? && total_spent_hours > 0)
1173
        total_spent_time_ratio =
1174
            total_spent_hours.to_f / total_estimated_hours.to_f * 100.0
1175
        total_spent_time_ratio.round(2)
1176
      end
1177
    end
1178
  end
1179

  
1149 1180
  def relations
1150 1181
    @relations ||= IssueRelation::Relations.new(self, (relations_from + relations_to).sort)
1151 1182
  end
......
1439 1470
    s << ' parent' unless leaf?
1440 1471
    s << ' private' if is_private?
1441 1472
    s << ' behind-schedule' if behind_schedule?
1473
    if user.allowed_to?(:view_time_entries, project, :global => true)
1474
      s << ' overspent' if overspent?
1475
      s << ' total-overspent' if total_overspent?
1476
    end
1442 1477
    if user.logged?
1443 1478
      s << ' created-by-me' if author_id == user.id
1444 1479
      s << ' assigned-to-me' if assigned_to_id == user.id
app/models/issue_query.rb
305 305
                        :default_order => 'desc',
306 306
                        :caption => :label_total_spent_time)
307 307
      )
308

  
309
      @available_columns.insert(
310
        index + 2,
311
        QueryColumn.new(:spent_time_ratio,
312
                        :caption => "Spent time ratio")
313
      )
314

  
315
      @available_columns.insert(
316
        index + 3,
317
        QueryColumn.new(:total_spent_time_ratio,
318
                        :caption => "Total spent time ratio")
319
      )
308 320
    end
309 321

  
310 322
    if User.current.allowed_to?(:set_issues_private, nil, :global => true) ||
......
399 411
    if has_column?(:total_spent_hours)
400 412
      Issue.load_visible_total_spent_hours(issues)
401 413
    end
414
    if has_column?(:spent_time_ratio)
415
      Issue.load_visible_spent_hours(issues)
416
    end
417
    if has_column?(:total_spent_time_ratio)
418
      Issue.load_visible_total_spent_hours(issues)
419
    end
402 420
    if has_column?(:last_updated_by)
403 421
      Issue.load_visible_last_updated_by(issues)
404 422
    end
app/models/version.rb
241 241
    @spent_hours ||= TimeEntry.joins(:issue).where("#{Issue.table_name}.fixed_version_id = ?", id).sum(:hours).to_f
242 242
  end
243 243

  
244
  def spent_time_ratio
245
    if (estimated_hours.present? && estimated_hours > 0)
246
      if (spent_hours.present? && spent_hours == 0)
247
        0.to_f.round(2)
248
      elsif (spent_hours.present? && spent_hours > 0)
249
        spent_time_ratio = spent_hours.to_f / estimated_hours.to_f * 100.0
250
        spent_time_ratio.round(2)
251
      end
252
    end
253
  end
254

  
244 255
  def closed?
245 256
    status == 'closed'
246 257
  end
app/views/issues/show.html.erb
73 73
  end
74 74
  if User.current.allowed_to?(:view_time_entries, @project) && @issue.total_spent_hours > 0
75 75
    rows.right l(:label_spent_time), issue_spent_hours_details(@issue), :class => 'spent-time'
76
    if spent_time_ratio_details(@issue).present?
77
      rows.right 'Spent time ratio', spent_time_ratio_details(@issue), :class => 'spent-time-ratio'
78
    end
76 79
  end
77 80
end %>
78 81
<%= render_half_width_custom_fields_rows(@issue) %>
app/views/versions/show.html.erb
28 28
    <td class="total-hours"><%= link_to html_hours(l_hours(@version.spent_hours)),
29 29
                                        project_time_entries_path(@version.project, :set_filter => 1, :"issue.fixed_version_id" => @version.id) %></td>
30 30
</tr>
31
<% if !@version.spent_time_ratio.nil? %>
32
<tr>
33
    <th><%= 'Spent time ratio' %></th>
34
    <% overspent_class = @version.spent_time_ratio > 100 ? 'overspent' : '' %>
35
    <td class="spent-time-ratio <%= overspent_class %>"><%= @version.spent_time_ratio.to_s(:percentage, precision: 2) %></td>
36
</tr>
37
<% end %>
31 38
<% end %>
32 39
</table>
33 40
</fieldset>
public/stylesheets/application.css
263 263
table.list td.reorder {width:15%; white-space:nowrap; text-align:center; }
264 264
table.list table.progress td {padding-right:0px;}
265 265
table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; }
266
table.list tr.overdue td.due_date  { color: #c22; }
266
table.list tr.overdue td.due_date,
267
table.list tr.overspent td.spent_time_ratio,
268
table.list tr.total-overspent td.total_spent_time_ratio,
269
div#version-summary td.spent-time-ratio.overspent { color: #c22; }
267 270
#role-permissions-trackers table.list th {white-space:normal;}
268 271

  
269 272
.table-list-cell {display: table-cell; vertical-align: top; padding:2px; }
......
540 543
div.issue .attributes .attribute {padding-left:180px; clear:left; min-height: 1.8em;}
541 544
div.issue .attributes .attribute .label {width: 170px; margin-left:-180px; font-weight:bold; float:left;  overflow:hidden; text-overflow: ellipsis;}
542 545
div.issue .attribute .value {overflow:auto; text-overflow: ellipsis;}
543
div.issue.overdue .due-date .value { color: #c22; }
546
div.issue.overdue .due-date .value,
547
div.issue.overspent .spent-time-ratio.attribute .value span.spent-time-ratio-value,
548
div.issue.total-overpent .spent-time-ratio.attribute .value, span.total-spent-time-ratio-value { color: #c22; }
544 549
body.controller-issues h2.inline-flex {padding-right: 0}
545 550

  
546 551
#issue_tree table.issues, #relations table.issues { border: 0; }
......
643 648
div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
644 649
div#version-summary fieldset { margin-bottom: 1em; }
645 650
div#version-summary fieldset.time-tracking table { width:100%; }
646
div#version-summary th, div#version-summary td.total-hours { text-align: right; }
651
div#version-summary th,
652
div#version-summary td.total-hours,
653
div#version-summary td.spent-time-ratio { text-align: right; }
647 654

  
648 655
table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
649 656
table#time-report tbody tr.subtotal { font-style: italic; color:#777;}
......
725 732
ul.properties li {list-style-type:none;}
726 733
ul.properties li span {font-style:italic;}
727 734

  
728
.total-hours { font-size: 110%; font-weight: bold; }
735
.total-hours,
736
div#version-summary .spent-time-ratio { font-size: 110%; font-weight: bold; }
729 737
.total-hours span.hours-int { font-size: 120%; }
730 738

  
731 739
.autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em; position: relative;}
(5-5/6)