You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
4.7 KiB

  1. # Copyright 2019 Eficent Business and IT Consulting Services S.L.
  2. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
  3. import datetime
  4. from datetime import timedelta
  5. from odoo.addons.resource.models.resource import ResourceCalendar
  6. from odoo.addons.resource.models.resource import to_naive_user_tz
  7. from odoo.tools.float_utils import float_compare
  8. def post_load_hook():
  9. def _new_schedule_days(self, days, day_dt, compute_leaves=False,
  10. resource_id=None):
  11. if not hasattr(self, '_get_schedule_days_iteration_limit'):
  12. return self._schedule_days_original(
  13. days, day_dt, compute_leaves=compute_leaves,
  14. resource_id=resource_id)
  15. # START OF HOOK: Introduce here the iterations limit
  16. iterations_limit = self._get_schedule_days_iteration_limit() or 100
  17. # END OF HOOK
  18. backwards = (days < 0)
  19. intervals = []
  20. planned_days, iterations = 0, 0
  21. day_dt_tz = to_naive_user_tz(day_dt, self.env.user)
  22. current_datetime = day_dt_tz.replace(
  23. hour=0, minute=0, second=0, microsecond=0)
  24. # HOOK. Use the iterations_limit here
  25. while planned_days < abs(days) and iterations < iterations_limit:
  26. working_intervals = self._get_day_work_intervals(
  27. current_datetime.date(),
  28. compute_leaves=compute_leaves, resource_id=resource_id)
  29. if not self or working_intervals:
  30. # no calendar -> no working hours, but day is
  31. # considered as worked
  32. planned_days += 1
  33. intervals += working_intervals
  34. # get next day
  35. if backwards:
  36. current_datetime = self._get_previous_work_day(
  37. current_datetime)
  38. else:
  39. current_datetime = self._get_next_work_day(current_datetime)
  40. # avoid infinite loops
  41. iterations += 1
  42. return intervals
  43. def _new_schedule_hours(self, hours, day_dt, compute_leaves=False,
  44. resource_id=None):
  45. if not hasattr(self, '_get_schedule_hours_iteration_limit'):
  46. return self._schedule_hours_original(
  47. hours, day_dt, compute_leaves=compute_leaves,
  48. resource_id=resource_id)
  49. self.ensure_one()
  50. # START OF HOOK: Introduce here the iterations limit
  51. iterations_limit = self._get_schedule_hours_iteration_limit() or 1000
  52. # END OF HOOK
  53. backwards = (hours < 0)
  54. intervals = []
  55. remaining_hours, iterations = abs(hours * 1.0), 0
  56. day_dt_tz = to_naive_user_tz(day_dt, self.env.user)
  57. current_datetime = day_dt_tz
  58. call_args = dict(compute_leaves=compute_leaves,
  59. resource_id=resource_id)
  60. # HOOK. Use the iterations_limit here
  61. while float_compare(remaining_hours, 0.0, precision_digits=2) in (
  62. 1, 0) and iterations < iterations_limit:
  63. if backwards:
  64. call_args['end_time'] = current_datetime.time()
  65. else:
  66. call_args['start_time'] = current_datetime.time()
  67. working_intervals = self._get_day_work_intervals(
  68. current_datetime.date(), **call_args)
  69. if working_intervals:
  70. new_working_intervals = self._interval_schedule_hours(
  71. working_intervals, remaining_hours, backwards=backwards)
  72. res = timedelta()
  73. for interval in working_intervals:
  74. res += interval[1] - interval[0]
  75. remaining_hours -= res.total_seconds() / 3600.0
  76. intervals = intervals + new_working_intervals if \
  77. not backwards else new_working_intervals + intervals
  78. # get next day
  79. if backwards:
  80. current_datetime = datetime.datetime.combine(
  81. self._get_previous_work_day(current_datetime),
  82. datetime.time(23, 59, 59))
  83. else:
  84. current_datetime = datetime.datetime.combine(
  85. self._get_next_work_day(current_datetime),
  86. datetime.time())
  87. # avoid infinite loops
  88. iterations += 1
  89. return intervals
  90. if not hasattr(ResourceCalendar, '_schedule_days_original'):
  91. ResourceCalendar._schedule_days_original = \
  92. ResourceCalendar._schedule_days
  93. ResourceCalendar._patch_method("_schedule_days", _new_schedule_days)
  94. if not hasattr(ResourceCalendar, '_schedule_hours_original'):
  95. ResourceCalendar._schedule_hours_original = \
  96. ResourceCalendar._schedule_hours
  97. ResourceCalendar._patch_method("_schedule_hours", _new_schedule_hours)