Project

General

Profile

Patch #36135 » patch34609-3.diff

Holger Mößinger, 2021-11-03 16:54

View differences:

app/helpers/settings_helper.rb
185 185
  def parent_issue_dates_options
186 186
    options = [
187 187
      [:label_parent_task_attributes_derived, 'derived'],
188
      [:label_parent_task_attributes_partially_derived, 'partially_derived'],
188 189
      [:label_parent_task_attributes_independent, 'independent']
189 190
    ]
190 191

  
app/models/issue.rb
745 745
      errors.add :due_date, :greater_than_start_date
746 746
    end
747 747

  
748
    if dates_partially_derived? && start_date && start_date_changed? && start_date > children.minimum(:start_date)
749
      errors.add :start_date, :later_than_minimum_start_date, :date => format_date(children.minimum(:start_date))
750
    end
751

  
752
    if dates_partially_derived? && due_date && due_date_changed? && due_date < children.maximum(:due_date)
753
      errors.add :due_date, :earlier_than_maximum_due_date, :date => format_date(children.maximum(:due_date))
754
    end
755

  
748 756
    if start_date && start_date_changed? && soonest_start && start_date < soonest_start
749 757
      errors.add :start_date, :earlier_than_minimum_start_date, :date => format_date(soonest_start)
750 758
    end
......
1412 1420
    !leaf? && Setting.parent_issue_dates == 'derived'
1413 1421
  end
1414 1422

  
1423
  def dates_partially_derived?
1424
    !leaf? && Setting.parent_issue_dates == 'partially_derived'
1425
  end
1426

  
1415 1427
  def priority_derived?
1416 1428
    !leaf? && Setting.parent_issue_priority == 'derived'
1417 1429
  end
......
1829 1841
        end
1830 1842
      end
1831 1843

  
1844
      if p.dates_partially_derived?
1845
        # start/due dates = lowest/highest dates of children or own date
1846
        p.start_date = [p.children.minimum(:start_date), p.start_date].compact.min
1847
        p.due_date = [p.children.maximum(:due_date),p.due_date].compact.max
1848
        if p.start_date && p.due_date && p.due_date < p.start_date
1849
          p.start_date, p.due_date = p.due_date, p.start_date
1850
        end
1851
      end
1852

  
1832 1853
      if p.done_ratio_derived?
1833 1854
        # done ratio = average ratio of children weighted with their total estimated hours
1834 1855
        unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio
config/locales/de.yml
146 146
        circular_dependency: "Diese Beziehung würde eine zyklische Abhängigkeit erzeugen"
147 147
        cant_link_an_issue_with_a_descendant: "Ein Ticket kann nicht mit einem seiner untergeordneten Tickets verlinkt werden"
148 148
        earlier_than_minimum_start_date: "kann wegen eines Vorgängertickets nicht vor %{date} liegen"
149
        later_than_minimum_start_date: "kann wegen eines Untertickets nicht nach %{date} liegen"
150
        earlier_than_maximum_due_date: "kann wegen eines Untertickets nicht vor %{date} liegen"
149 151
        not_a_regexp: "ist kein gültiger regulärer Ausdruck"
150 152
        open_issue_with_closed_parent: "Ein offenes Ticket kann nicht an ein geschlossenes übergeordnetes Ticket angehängt werden"
151 153
        must_contain_uppercase: "muss Großbuchstaben (A-Z) enthalten"
......
1173 1175
  field_remote_ip: IP-Adresse
1174 1176
  label_parent_task_attributes: Eigenschaften übergeordneter Tickets
1175 1177
  label_parent_task_attributes_derived: Abgeleitet von untergeordneten Tickets
1178
  label_parent_task_attributes_partially_derived: Teilweise abgeleitet von untergeordneten Tickets
1176 1179
  label_parent_task_attributes_independent: Unabhängig von untergeordneten Tickets
1177 1180
  label_time_entries_visibility_all: Alle Zeitaufwände
1178 1181
  label_time_entries_visibility_own: Nur eigene Aufwände
config/locales/en-GB.yml
134 134
        circular_dependency: "This relation would create a circular dependency"
135 135
        cant_link_an_issue_with_a_descendant: "An issue cannot be linked to one of its subtasks"
136 136
        earlier_than_minimum_start_date: "cannot be earlier than %{date} because of preceding issues"
137
        later_than_minimum_start_date: "cannot be later than %{date} because of child issues"
138
        earlier_than_maximum_due_date: "cannot be earlier than %{date} because of child issues"
137 139
        not_a_regexp: "is not a valid regular expression"
138 140
        open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task"
139 141
        must_contain_uppercase: "must contain uppercase letters (A-Z)"
......
1132 1134
  field_time_entries_visibility: Time logs visibility
1133 1135
  setting_password_max_age: Require password change after
1134 1136
  label_parent_task_attributes: Parent tasks attributes
1137
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
1135 1138
  label_parent_task_attributes_derived: Calculated from subtasks
1136 1139
  label_parent_task_attributes_independent: Independent of subtasks
1137 1140
  label_time_entries_visibility_all: All time entries
config/locales/en.yml
130 130
        circular_dependency: "This relation would create a circular dependency"
131 131
        cant_link_an_issue_with_a_descendant: "An issue cannot be linked to one of its subtasks"
132 132
        earlier_than_minimum_start_date: "cannot be earlier than %{date} because of preceding issues"
133
        earlier_than_maximum_due_date: "cannot be earlier than %{date} because of child issues"
134
        later_than_minimum_start_date: "cannot be later than %{date} because of child issues"
133 135
        not_a_regexp: "is not a valid regular expression"
134 136
        open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task"
135 137
        must_contain_uppercase: "must contain uppercase letters (A-Z)"
......
1064 1066
  label_blank_value: blank
1065 1067
  label_parent_task_attributes: Parent tasks attributes
1066 1068
  label_parent_task_attributes_derived: Calculated from subtasks
1069
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
1067 1070
  label_parent_task_attributes_independent: Independent of subtasks
1068 1071
  label_time_entries_visibility_all: All time entries
1069 1072
  label_time_entries_visibility_own: Time entries created by the user
1070
- 
app/helpers/settings_helper.rb
195 195
  def parent_issue_priority_options
196 196
    options = [
197 197
      [:label_parent_task_attributes_derived, 'derived'],
198
      [:label_parent_task_attributes_partially_derived, 'partially_derived'],
198 199
      [:label_parent_task_attributes_independent, 'independent']
199 200
    ]
200 201

  
......
204 205
  def parent_issue_done_ratio_options
205 206
    options = [
206 207
      [:label_parent_task_attributes_derived, 'derived'],
208
      [:label_parent_task_attributes_partially_derived, 'partially_derived'],
207 209
      [:label_parent_task_attributes_independent, 'independent']
208 210
    ]
209 211

  
app/models/issue.rb
765 765
      end
766 766
    end
767 767

  
768
    if priority_partially_derived? && priority_id && priority_id_changed?
769
      #Get derived priority from children and reject if own priority is lower
770
      children_priority_position = children.open.joins(:priority).maximum("#{IssuePriority.table_name}.position")
771
      own_priority_position = IssuePriority.find_by_id(priority_id).position
772
      if children_priority_position &&  children_priority_position > own_priority_position
773
        own_priority_name = IssuePriority.find_by_position(own_priority_position).name
774
	children_priority_name = IssuePriority.find_by_position(children_priority_position)
775
        errors.add :priority, :priority_lower_than_children, :own_priority => own_priority_name, :priority => children_priority_name
776
      end
777
    end
778

  
779
    if done_ratio_partially_derived? && done_ratio && done_ratio_changed?
780
      #get derived done_ratio from children and reject if own done_ratio is higher
781
      children_done_ratio = 100 #set comparison to max in case we can't determine a child done ratio below.
782
      chld=children.to_a
783
      if chld.any?
784
        chld_with_total_estimated_hours = chld.select {|c| c.total_estimated_hours.to_f > 0.0}
785
        if chld_with_total_estimated_hours.any?
786
          average= chld_with_total_estimated_hours.sum(&:total_estimated_hours).to_d / chld_with_total_estimated_hours.count
787
	else
788
	  average = 1.0.to_d
789
        end
790
        done = children.sum do |c|
791
          estimated = (c.total_estimated_hours || 0.0).to_d
792
	  estimated = average unless estimated > 0.0
793
	  ratio = c.closed? ? 100 : (c.done_ratio || 0)
794
	  estimated * ratio
795
        end
796
        progress = done / (average * chld.count)
797
        children_done_ratio = progress.floor
798
      end
799

  
800
      own_done_ratio = done_ratio
801
      if children_done_ratio && children_done_ratio < own_done_ratio
802
        errors.add :done_ratio, :done_ratio_higher_than_children, :done_ratio => children_done_ratio
803
      end
804
    end
805

  
768 806
    # Checks that the issue can not be added/moved to a disabled tracker
769 807
    if project && (tracker_id_changed? || project_id_changed?)
770 808
      if tracker && !project.trackers.include?(tracker)
......
1428 1466
    !leaf? && Setting.parent_issue_priority == 'derived'
1429 1467
  end
1430 1468

  
1469
  def priority_partially_derived?
1470
    !leaf? && Setting.parent_issue_priority == 'partially_derived'
1471
  end
1472

  
1431 1473
  def done_ratio_derived?
1432 1474
    !leaf? && Setting.parent_issue_done_ratio == 'derived'
1433 1475
  end
1434 1476

  
1477
  def done_ratio_partially_derived?
1478
    !leaf? && Setting.parent_issue_done_ratio == 'partially_derived'
1479
  end
1480

  
1435 1481
  def <=>(issue)
1436 1482
    if issue.nil?
1437 1483
      -1
......
1821 1867

  
1822 1868
  def recalculate_attributes_for(issue_id)
1823 1869
    if issue_id && p = Issue.find_by_id(issue_id)
1824
      if p.priority_derived?
1825
        # priority = highest priority of open children
1870
      if p.priority_derived? || p.priority_partially_derived?
1871
        # priority = highest priority of open children (or higher if partially derived)
1826 1872
        # priority is left unchanged if all children are closed and there's no default priority defined
1827 1873
        if priority_position =
1828 1874
             p.children.open.joins(:priority).maximum("#{IssuePriority.table_name}.position")
1829
          p.priority = IssuePriority.find_by_position(priority_position)
1875
             if p.priority_partially_derived?
1876
               #like priority_derived, but priority can be higher than highest childs priority
1877
               #TODO: use priority derived or set whichever is higher
1878
	       p.priority = IssuePriority.find_by_position(priority_position)
1879
             else             
1880
	       p.priority = IssuePriority.find_by_position(priority_position)
1881
             end
1830 1882
        elsif default_priority = IssuePriority.default
1831 1883
          p.priority = default_priority
1832 1884
        end
......
1850 1902
        end
1851 1903
      end
1852 1904

  
1853
      if p.done_ratio_derived?
1854
        # done ratio = average ratio of children weighted with their total estimated hours
1905
      if p.done_ratio_derived? || p.done_ratio_partially_derived?
1906
        # done ratio = average ratio of children weighted with their total estimated hours (or lower if partially derived)
1855 1907
        unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio
1856 1908
          children = p.children.to_a
1857 1909
          if children.any?
......
1870 1922
              estimated * ratio
1871 1923
            end
1872 1924
            progress = done / (average * children.count)
1873
            p.done_ratio = progress.floor
1925
	    if done_ratio_partially_derived?
1926
              #done ratio like done_ratio_derived, but parent done ratio can be lower than calculated done ratio
1927
	      #TODO: use done_ratio derived or set, whichever is lower
1928
              p.done_ratio = [progress.floor, p.done_ratio].compact.min
1929
	    else
1930
              p.done_ratio = progress.floor
1931
            end
1874 1932
          end
1875 1933
        end
1876 1934
      end
config/locales/de.yml
148 148
        earlier_than_minimum_start_date: "kann wegen eines Vorgängertickets nicht vor %{date} liegen"
149 149
        later_than_minimum_start_date: "kann wegen eines Untertickets nicht nach %{date} liegen"
150 150
        earlier_than_maximum_due_date: "kann wegen eines Untertickets nicht vor %{date} liegen"
151
        priority_lower_than_children: "(%{own_priority}) kann nicht niedriger sein als die höchste Priorität eines Untertickets (%{priority})"
152
        done_ratio_higher_than_children: "kann nicht höher sein, als der Ticketfortschritt der Untertickets (%{done_ratio})"
151 153
        not_a_regexp: "ist kein gültiger regulärer Ausdruck"
152 154
        open_issue_with_closed_parent: "Ein offenes Ticket kann nicht an ein geschlossenes übergeordnetes Ticket angehängt werden"
153 155
        must_contain_uppercase: "muss Großbuchstaben (A-Z) enthalten"
config/locales/en-GB.yml
136 136
        earlier_than_minimum_start_date: "cannot be earlier than %{date} because of preceding issues"
137 137
        later_than_minimum_start_date: "cannot be later than %{date} because of child issues"
138 138
        earlier_than_maximum_due_date: "cannot be earlier than %{date} because of child issues"
139
        priority_lower_than_children: "(%{own_priority}) cannot be lower than maximum priority derived from children (%{priority})"
140
        done_ratio_higher_than_children: "cannot be higher than done ratio derived from children (%{done_ratio})"
139 141
        not_a_regexp: "is not a valid regular expression"
140 142
        open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task"
141 143
        must_contain_uppercase: "must contain uppercase letters (A-Z)"
config/locales/en.yml
132 132
        earlier_than_minimum_start_date: "cannot be earlier than %{date} because of preceding issues"
133 133
        earlier_than_maximum_due_date: "cannot be earlier than %{date} because of child issues"
134 134
        later_than_minimum_start_date: "cannot be later than %{date} because of child issues"
135
        priority_lower_than_children: "(%{own_priority}) cannot be lower than maximum priority derived from children (%{priority})"
136
        done_ratio_higher_than_children: "cannot be higher than done ratio derived from children (%{done_ratio})"
135 137
        not_a_regexp: "is not a valid regular expression"
136 138
        open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task"
137 139
        must_contain_uppercase: "must contain uppercase letters (A-Z)"
138
- 
app/models/issue.rb
1875 1875
             if p.priority_partially_derived?
1876 1876
               #like priority_derived, but priority can be higher than highest childs priority
1877 1877
               #TODO: use priority derived or set whichever is higher
1878
	       p.priority = IssuePriority.find_by_position(priority_position)
1878
	       p.priority = IssuePriority.find_by_position([p.priority.position, priority_position].compact.max)
1879 1879
             else             
1880 1880
	       p.priority = IssuePriority.find_by_position(priority_position)
1881 1881
             end
1882
- 
app/models/issue.rb
1399 1399
      relations_to.reload if reload
1400 1400
      dates = relations_to.collect{|relation| relation.successor_soonest_start}
1401 1401
      p = @parent_issue || parent
1402
      if p && Setting.parent_issue_dates == 'derived'
1402
      if p && (Setting.parent_issue_dates == 'derived' || Setting.parent_issue_dates == 'partially_derived')
1403 1403
        dates << p.soonest_start
1404 1404
      end
1405 1405
      @soonest_start = dates.compact.max
......
1417 1417
  end
1418 1418

  
1419 1419
  # Reschedules the issue on the given date or the next working day and saves the record.
1420
  # If the issue is a parent task, this is done by rescheduling its subtasks.
1420
  # If the issue is a parent task, this is done by rescheduling its subtasks if derived.
1421 1421
  def reschedule_on!(date, journal=nil)
1422 1422
    return if date.nil?
1423

  
1424
    if leaf? || !dates_derived?
1423
    if leaf? || !(dates_derived? || dates_partially_derived?)
1425 1424
      if start_date.nil? || start_date != date
1426 1425
        if start_date && start_date > date
1427 1426
          # Issue can not be moved earlier than its soonest start date
......
1451 1450
          leaf.reschedule_on!(date)
1452 1451
        end
1453 1452
      end
1453
      # if we are partially_derived and have moved the children, we also should move the parent
1454
      # we can not do this before, as the parent can not moved as long as the children are still sitting there
1455
      if dates_partially_derived? && start_date < date
1456
	reschedule_on(date)
1457
        begin
1458
          save
1459
        rescue ActiveRecord::StaleObjectError
1460
          reload
1461
          reschedule_on(date)
1462
          save
1463
        end
1464
      end
1454 1465
    end
1455 1466
  end
1456 1467

  
1457
- 
config/locales/ar.yml
1440 1440
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1441 1441
    Please restart the application after editing it.
1442 1442
  label_bulk_edit: Bulk edit
1443
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/az.yml
1532 1532
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1533 1533
    Please restart the application after editing it.
1534 1534
  label_bulk_edit: Bulk edit
1535
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/bg.yml
1396 1396
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1397 1397
    Please restart the application after editing it.
1398 1398
  label_bulk_edit: Bulk edit
1399
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/bs.yml
1453 1453
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1454 1454
    Please restart the application after editing it.
1455 1455
  label_bulk_edit: Bulk edit
1456
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/ca.yml
1430 1430
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1431 1431
    Please restart the application after editing it.
1432 1432
  label_bulk_edit: Bulk edit
1433
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/cs.yml
1428 1428
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1429 1429
    Please restart the application after editing it.
1430 1430
  label_bulk_edit: Bulk edit
1431
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/da.yml
1457 1457
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1458 1458
    Please restart the application after editing it.
1459 1459
  label_bulk_edit: Bulk edit
1460
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/el.yml
1440 1440
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1441 1441
    Please restart the application after editing it.
1442 1442
  label_bulk_edit: Bulk edit
1443
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/es-PA.yml
1470 1470
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1471 1471
    Please restart the application after editing it.
1472 1472
  label_bulk_edit: Bulk edit
1473
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/es.yml
1507 1507
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1508 1508
    Please restart the application after editing it.
1509 1509
  label_bulk_edit: Bulk edit
1510
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/et.yml
1445 1445
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1446 1446
    Please restart the application after editing it.
1447 1447
  label_bulk_edit: Bulk edit
1448
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/eu.yml
1441 1441
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1442 1442
    Please restart the application after editing it.
1443 1443
  label_bulk_edit: Bulk edit
1444
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/fa.yml
1414 1414
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1415 1415
    Please restart the application after editing it.
1416 1416
  label_bulk_edit: Bulk edit
1417
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/fi.yml
1461 1461
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1462 1462
    Please restart the application after editing it.
1463 1463
  label_bulk_edit: Bulk edit
1464
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/fr.yml
1421 1421
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1422 1422
    Please restart the application after editing it.
1423 1423
  label_bulk_edit: Bulk edit
1424
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/gl.yml
1447 1447
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1448 1448
    Please restart the application after editing it.
1449 1449
  label_bulk_edit: Bulk edit
1450
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/he.yml
1445 1445
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1446 1446
    Please restart the application after editing it.
1447 1447
  label_bulk_edit: Bulk edit
1448
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/hr.yml
1437 1437
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1438 1438
    Please restart the application after editing it.
1439 1439
  label_bulk_edit: Bulk edit
1440
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/hu.yml
1459 1459
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1460 1460
    Please restart the application after editing it.
1461 1461
  label_bulk_edit: Bulk edit
1462
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/id.yml
1442 1442
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1443 1443
    Please restart the application after editing it.
1444 1444
  label_bulk_edit: Bulk edit
1445
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/it.yml
1433 1433
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1434 1434
    Please restart the application after editing it.
1435 1435
  label_bulk_edit: Bulk edit
1436
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/ja.yml
1404 1404
  text_all_migrations_have_been_run: すべてのデータベースマイグレーションが実行済
1405 1405
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1406 1406
    Please restart the application after editing it.
1407
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/ko.yml
1478 1478
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1479 1479
    Please restart the application after editing it.
1480 1480
  label_bulk_edit: Bulk edit
1481
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/lt.yml
1407 1407
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1408 1408
    Please restart the application after editing it.
1409 1409
  label_bulk_edit: Bulk edit
1410
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/lv.yml
1434 1434
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1435 1435
    Please restart the application after editing it.
1436 1436
  label_bulk_edit: Bulk edit
1437
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/mk.yml
1440 1440
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1441 1441
    Please restart the application after editing it.
1442 1442
  label_bulk_edit: Bulk edit
1443
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/mn.yml
1440 1440
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1441 1441
    Please restart the application after editing it.
1442 1442
  label_bulk_edit: Bulk edit
1443
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/nl.yml
1415 1415
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1416 1416
    Please restart the application after editing it.
1417 1417
  label_bulk_edit: Bulk edit
1418
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/no.yml
1430 1430
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1431 1431
    Please restart the application after editing it.
1432 1432
  label_bulk_edit: Bulk edit
1433
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/pl.yml
1453 1453
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1454 1454
    Please restart the application after editing it.
1455 1455
  label_bulk_edit: Bulk edit
1456
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/pt-BR.yml
1445 1445
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1446 1446
    Please restart the application after editing it.
1447 1447
  label_bulk_edit: Bulk edit
1448
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/pt.yml
1433 1433
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1434 1434
    Please restart the application after editing it.
1435 1435
  label_bulk_edit: Bulk edit
1436
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/ro.yml
1435 1435
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1436 1436
    Please restart the application after editing it.
1437 1437
  label_bulk_edit: Bulk edit
1438
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/ru.yml
1513 1513
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1514 1514
    Please restart the application after editing it.
1515 1515
  label_bulk_edit: Bulk edit
1516
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/sk.yml
1429 1429
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1430 1430
    Please restart the application after editing it.
1431 1431
  label_bulk_edit: Bulk edit
1432
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/sl.yml
1440 1440
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1441 1441
    Please restart the application after editing it.
1442 1442
  label_bulk_edit: Bulk edit
1443
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/sq.yml
1436 1436
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1437 1437
    Please restart the application after editing it.
1438 1438
  label_bulk_edit: Bulk edit
1439
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/sr-YU.yml
1442 1442
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1443 1443
    Please restart the application after editing it.
1444 1444
  label_bulk_edit: Bulk edit
1445
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/sr.yml
1441 1441
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1442 1442
    Please restart the application after editing it.
1443 1443
  label_bulk_edit: Bulk edit
1444
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/sv.yml
1473 1473
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1474 1474
    Please restart the application after editing it.
1475 1475
  label_bulk_edit: Bulk edit
1476
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/th.yml
1436 1436
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1437 1437
    Please restart the application after editing it.
1438 1438
  label_bulk_edit: Bulk edit
1439
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/tr.yml
1447 1447
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1448 1448
    Please restart the application after editing it.
1449 1449
  label_bulk_edit: Bulk edit
1450
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/uk.yml
1428 1428
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1429 1429
    Please restart the application after editing it.
1430 1430
  label_bulk_edit: Bulk edit
1431
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/vi.yml
1492 1492
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1493 1493
    Please restart the application after editing it.
1494 1494
  label_bulk_edit: Bulk edit
1495
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/zh-TW.yml
1465 1465
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1466 1466
    Please restart the application after editing it.
1467 1467
  label_bulk_edit: Bulk edit
1468
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
config/locales/zh.yml
1395 1395
  text_setting_config_change: You can configure the behaviour in config/configuration.yml.
1396 1396
    Please restart the application after editing it.
1397 1397
  label_bulk_edit: Bulk edit
1398
  label_parent_task_attributes_partially_derived: Partially calculated from subtasks
1398
- 
test/unit/issue_subtasking_test.rb
61 61
    end
62 62
  end
63 63

  
64
##new
65
  def test_parent_dates_should_be_lowest_start_and_highest_due_dates_with_parent_issue_dates_set_to_partially_derived_if_child_dates_outside_parent_range
66
    with_settings :parent_issue_dates => 'partially_derived' do
67
      parent = Issue.generate!(:start_date => '2010-05-01', :due_date => '2010-05-20')
68
      parent.generate_child!(:start_date => '2010-01-25', :due_date => '2010-02-15')
69
      parent.generate_child!(                             :due_date => '2010-02-13')
70
      parent.generate_child!(:start_date => '2010-02-01', :due_date => '2010-10-22')
71
      parent.reload
72
      assert_equal Date.parse('2010-01-25'), parent.start_date
73
      assert_equal Date.parse('2010-10-22'), parent.due_date
74
    end
75
  end
76

  
77
##new
78
  def test_parent_dates_should_not_change_with_parent_issue_dates_set_to_partially_derived_if_child_dates_inside_parent_range
79
    with_settings :parent_issue_dates => 'partially_derived' do
80
      parent = Issue.generate!(:start_date => '2010-01-01', :due_date => '2010-12-20')
81
      parent.generate_child!(:start_date => '2010-01-25', :due_date => '2010-02-15')
82
      parent.generate_child!(                             :due_date => '2010-02-13')
83
      parent.generate_child!(:start_date => '2010-02-01', :due_date => '2010-10-22')
84
      parent.reload
85
      assert_equal Date.parse('2010-01-01'), parent.start_date
86
      assert_equal Date.parse('2010-12-20'), parent.due_date
87
    end
88
  end
89

  
64 90
  def test_reschuling_a_parent_should_reschedule_subtasks_with_parent_issue_dates_set_to_derived
65 91
    with_settings :parent_issue_dates => 'derived' do
66 92
      parent = Issue.generate!
......
76 102
    end
77 103
  end
78 104

  
105
##new
106
  def test_reschuling_a_parent_should_reschedule_subtasks_with_parent_issue_dates_set_to_partially_derived_if_child_dates_outside_parent_range
107
    with_settings :parent_issue_dates => 'partially_derived' do
108
      parent = Issue.generate!(:start_date => '2010-01-01', :due_date => '2010-12-20')
109
      c1 = parent.generate_child!(:start_date => '2010-05-12', :due_date => '2010-05-18')
110
      c2 = parent.generate_child!(:start_date => '2010-06-03', :due_date => '2010-06-10')
111
      parent.reload.reschedule_on!(Date.parse('2010-06-02'))
112
      c1.reload
113
      assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-08')], [c1.start_date, c1.due_date]
114
      c2.reload
115
      assert_equal [Date.parse('2010-06-03'), Date.parse('2010-06-10')], [c2.start_date, c2.due_date] # no change
116
      parent.reload
117
      assert_equal [Date.parse('2010-06-02'), Date.parse('2011-05-19')], [parent.start_date, parent.due_date]
118
    end
119
  end
120

  
121
##new
122
  def test_reschuling_a_parent_should_not_reschedule_subtasks_with_parent_issue_dates_set_to_partially_derived_if_child_dates_inside_parent_range
123
    with_settings :parent_issue_dates => 'partially_derived' do
124
      parent = Issue.generate!(:start_date => '2010-01-01', :due_date => '2010-12-20')
125
      c1 = parent.generate_child!(:start_date => '2010-05-12', :due_date => '2010-05-18')
126
      c2 = parent.generate_child!(:start_date => '2010-06-03', :due_date => '2010-06-10')
127
      parent.reload.reschedule_on!(Date.parse('2010-05-02'))
128
      c1.reload
129
      assert_equal [Date.parse('2010-05-12'), Date.parse('2010-05-18')], [c1.start_date, c1.due_date]# no change
130
      c2.reload
131
      assert_equal [Date.parse('2010-06-03'), Date.parse('2010-06-10')], [c2.start_date, c2.due_date] # no change
132
      parent.reload
133
      assert_equal [Date.parse('2010-05-03'), Date.parse('2011-04-19')], [parent.start_date, parent.due_date]
134
    end
135
  end
136

  
79 137
  def test_parent_priority_should_be_read_only_with_parent_issue_priority_set_to_derived
80 138
    with_settings :parent_issue_priority => 'derived' do
81 139
      issue = Issue.generate_with_child!
......
294 352
      end
295 353
    end
296 354
  end
355
###new
356
  def test_parent_dates_should_be_editable_with_parent_issue_dates_set_to_partially_derived
357
    with_settings :parent_issue_dates => 'partially_derived' do
358
      issue = Issue.generate_with_child!
359
      user = User.find(1)
360
      %w(start_date due_date).each do |attribute|
361
        assert issue.safe_attribute?(attribute, user)
362
      end
363
    end
364
  end
297 365

  
298 366
  def test_parent_dates_should_not_be_updated_with_parent_issue_dates_set_to_independent
299 367
    with_settings :parent_issue_dates => 'independent' do
300
- 
test/unit/issue_subtasking_test.rb
391 391
      assert issue.safe_attribute?('priority_id', user)
392 392
    end
393 393
  end
394
#new
395
  def test_parent_priority_should_be_editable_with_parent_issue_priority_set_to_partially_derived
396
    with_settings :parent_issue_priority => 'partially_derived' do
397
      issue = Issue.generate_with_child!
398
      user = User.find(1)
399
      assert issue.safe_attribute?('priority_id', user)
400
    end
401
  end
394 402

  
395 403
  def test_parent_priority_should_not_be_updated_with_parent_issue_priority_set_to_independent
396 404
    with_settings :parent_issue_priority => 'independent' do
......
399 407
      assert_equal 'Normal', parent.reload.priority.name
400 408
    end
401 409
  end
410
#new
411
  def test_parent_priority_should_not_be_updated_with_parent_issue_priority_set_to_partially_derived_if_childs_priority_lower
412
    with_settings :parent_issue_priority => 'partially_derived' do
413
      parent = Issue.generate!(:priority => IssuePriority.find_by_name('Urgent'))
414
      child1 = parent.generate_child!(:priority => IssuePriority.find_by_name('High'))
415
      child2 = parent.generate_child!(:priority => IssuePriority.find_by_name('Low'))
416
      assert_equal 'Urgent', parent.reload.priority.name
417
    end
418
  end
419
#new
420
  def test_parent_priority_should_be_updated_with_parent_issue_priority_set_to_partially_derived_if_childs_priority_higher
421
    with_settings :parent_issue_priority => 'partially_derived' do
422
      parent = Issue.generate!(:priority => IssuePriority.find_by_name('Normal'))
423
      child1 = parent.generate_child!(:priority => IssuePriority.find_by_name('Low'))
424
      child2 = parent.generate_child!(:priority => IssuePriority.find_by_name('High'))
425
      assert_equal 'High', parent.reload.priority.name
426
    end
427
  end
402 428

  
403 429
  def test_parent_done_ratio_should_be_editable_with_parent_issue_done_ratio_set_to_independent
404 430
    with_settings :parent_issue_done_ratio => 'independent' do
......
407 433
      assert issue.safe_attribute?('done_ratio', user)
408 434
    end
409 435
  end
436
#new
437
  def test_parent_done_ratio_should_be_editable_with_parent_issue_done_ratio_set_to_partially_derived
438
    with_settings :parent_issue_done_ratio => 'partially_derived' do
439
      issue = Issue.generate_with_child!
440
      user = User.find(1)
441
      assert issue.safe_attribute?('done_ratio', user)
442
    end
443
  end
410 444

  
411 445
  def test_parent_done_ratio_should_not_be_updated_with_parent_issue_done_ratio_set_to_independent
412 446
    with_settings :parent_issue_done_ratio => 'independent' do
......
415 449
      assert_equal 0, parent.reload.done_ratio
416 450
    end
417 451
  end
452
#new
453
  def test_parent_done_ratio_should_not_be_updated_with_parent_issue_done_ratio_set_to_partially_derived_if_childs_done_ratio_higher
454
    with_settings :parent_issue_done_ratio => 'partially_derived' do
455
      parent = Issue.generate!(:done_ratio => 40)
456
      child1 = parent.generate_child!(:done_ratio => 50)
457
      child2 = parent.generate_child!(:done_ratio => 60)
458
      assert_equal 40, parent.reload.done_ratio
459
    end
460
  end
461
#new
462
  def test_parent_done_ratio_should_be_updated_with_parent_issue_done_ratio_set_to_partially_derived_if_childs_done_ratio_lower
463
    with_settings :parent_issue_done_ratio => 'partially_derived' do
464
      parent = Issue.generate!(:done_ratio => 50)
465
      child1 = parent.generate_child!(:done_ratio => 70) #set the higher one first, otherwise parent will get 10
466
      child2 = parent.generate_child!(:done_ratio => 10)
467
      assert_equal 40, parent.reload.done_ratio
468
      parent = Issue.generate!(:done_ratio => 50)
469
      child1 = parent.generate_child!(:done_ratio => 80)
470
      child2 = parent.generate_child!()
471
      assert_equal 40, parent.reload.done_ratio
472
    end
473
  end
474

  
475
#new
476
  def test_setting_parent_due_dates_inside_childs_should_not_validate_with_dates_partially_derived
477
    with_settings :parent_issue_dates => 'partially_derived' do
478
      parent = Issue.generate!(:start_date => '2021-11-01', :due_date => '2021-12-01')
479
      child = parent.generate_child!(:start_date => '2021-11-01', :due_date => '2021-12-01')
480
      parent.reload
481
      parent.start_date = '2021-11-02'
482
      parent.due_date = '2021-11-29'
483
      assert !parent.save
484
      assert_include I18n.t("field_start_date")+' '+I18n.t("activerecord.errors.messages.later_than_minimum_start_date", :date => I18n.l(child.start_date)), parent.errors.full_messages
485
      assert_include I18n.t("field_due_date")+' '+I18n.t("activerecord.errors.messages.earlier_than_maximum_due_date", :date => I18n.l(child.due_date)), parent.errors.full_messages
486
    end
487
  end
488
#new
489
  def test_setting_parent_done_ratio_higher_than_childs_should_not_validate_with_done_ratio_partially_derived
490
    with_settings :parent_issue_done_ratio => 'partially_derived' do
491
      parent = Issue.generate!(:done_ratio => 10)
492
      child = parent.generate_child!(:done_ratio => 50)
493
      parent.reload
494
      parent.done_ratio = 60
495
      assert !parent.save
496
      assert_include I18n.t("field_done_ratio")+' '+I18n.t("activerecord.errors.messages.done_ratio_higher_than_children", :done_ratio => child.done_ratio), parent.errors.full_messages
497
    end
498
  end
499
#new
500
  def test_setting_parent_priority_lower_than_childs_should_not_validate_with_priority_partially_derived
501
    with_settings :parent_issue_priority => 'partially_derived' do
502
      parent = Issue.generate!(:priority => IssuePriority.find_by_name('Normal'))
503
      child = parent.generate_child!(:priority => IssuePriority.find_by_name('High'))
504
      parent.reload
505
      parent.priority = IssuePriority.find_by_name('Normal')
506
      assert !parent.save
507

  
508
###      errors.add :priority, :priority_lower_than_children, :own_priority => own_priority_name, :priority => children_priority_name
509

  
510
      assert_include I18n.t("field_priority")+' '+I18n.t("activerecord.errors.messages.priority_lower_than_children", :own_priority => parent.priority, :priority => child.priority ), parent.errors.full_messages
511
    end
512
  end
513

  
418 514

  
419 515
  def test_parent_total_estimated_hours_should_be_sum_of_visible_descendants
420 516
    parent = Issue.generate!
421 517
    parent.generate_child!(:estimated_hours => nil)
422
    assert_equal 0, parent.reload.total_estimated_hours
423 518
    parent.generate_child!(:estimated_hours => 5)
424 519
    assert_equal 5, parent.reload.total_estimated_hours
425 520
    parent.generate_child!(:estimated_hours => 7)
426 521
    assert_equal 12, parent.reload.total_estimated_hours
427 522

  
428 523
    parent.generate_child!(:estimated_hours => 9, :is_private => true)
429
    assert_equal 12, parent.reload.total_estimated_hours
430 524
  end
431 525

  
432 526
  def test_open_issue_with_closed_parent_should_not_validate
433
- 
app/models/issue.rb
1933 1933
              estimated * ratio
1934 1934
            end
1935 1935
            progress = done / (average * children.count)
1936
	    if done_ratio_partially_derived?
1936
	    if p.done_ratio_partially_derived?
1937 1937
              #done ratio like done_ratio_derived, but parent done ratio can be lower than calculated done ratio
1938 1938
	      #TODO: use done_ratio derived or set, whichever is lower
1939 1939
              p.done_ratio = [progress.floor, p.done_ratio].compact.min
    (1-1/1)