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.

284 lines
13 KiB

  1. from odoo import models, fields, api, _
  2. from odoo.addons.beesdoo_shift.models.cooperative_status import add_days_delta
  3. from odoo.exceptions import ValidationError, UserError
  4. from datetime import timedelta, datetime
  5. import logging
  6. class CooperativeStatus(models.Model):
  7. _inherit = 'cooperative.status'
  8. _period = 28
  9. ######################################################
  10. # #
  11. # Override of method to define status behavior #
  12. # #
  13. ######################################################
  14. future_alert_date = fields.Date(compute='_compute_future_alert_date')
  15. next_countdown_date = fields.Date(compute='_compute_next_countdown_date')
  16. @api.depends('today', 'irregular_start_date', 'sr', 'holiday_start_time',
  17. 'holiday_end_time', 'temporary_exempt_start_date',
  18. 'temporary_exempt_end_date')
  19. def _compute_future_alert_date(self):
  20. """Compute date before which the worker is up to date"""
  21. for rec in self:
  22. # Only for irregular worker
  23. if rec.working_mode != 'irregular' and not rec.irregular_start_date:
  24. rec.future_alert_date = False
  25. # Alert start time already set
  26. elif rec.alert_start_time:
  27. rec.future_alert_date = False
  28. # Holidays are not set properly
  29. elif bool(rec.holiday_start_time) != bool(rec.holiday_end_time):
  30. rec.future_alert_date = False
  31. # Exemption have not a start and end time
  32. elif (bool(rec.temporary_exempt_start_date)
  33. != bool(rec.temporary_exempt_end_date)):
  34. rec.future_alert_date = False
  35. else:
  36. date = rec.today
  37. counter = rec.sr
  38. # Simulate the countdown
  39. while counter > 0:
  40. date = self._next_countdown_date(
  41. rec.irregular_start_date, date
  42. )
  43. # Check holidays
  44. if (
  45. rec.holiday_start_time and rec.holiday_end_time
  46. and date >= rec.holiday_start_time
  47. and date <= rec.holiday_end_time
  48. ):
  49. date = add_days_delta(date, 1)
  50. continue
  51. # Check temporary exemption
  52. if (
  53. rec.temporary_exempt_start_date
  54. and rec.temporary_exempt_end_date
  55. and date >= rec.temporary_exempt_start_date
  56. and date <= rec.temporary_exempt_end_date
  57. ):
  58. date = add_days_delta(date, 1)
  59. continue
  60. # Otherwise
  61. date = add_days_delta(date, 1)
  62. counter -= 1
  63. rec.future_alert_date = self._next_countdown_date(
  64. rec.irregular_start_date, date
  65. )
  66. @api.depends('today', 'irregular_start_date', 'holiday_start_time',
  67. 'holiday_end_time', 'temporary_exempt_start_date',
  68. 'temporary_exempt_end_date')
  69. def _compute_next_countdown_date(self):
  70. """
  71. Compute the following countdown date. This date is the date when
  72. the worker will see his counter changed du to the cron. This
  73. date is like the birthday date of the worker that occurred each
  74. PERIOD.
  75. """
  76. for rec in self:
  77. # Only for irregular worker
  78. if rec.working_mode != 'irregular' and not rec.irregular_start_date:
  79. rec.next_countdown_date = False
  80. # Holidays are not set properly
  81. elif bool(rec.holiday_start_time) != bool(rec.holiday_end_time):
  82. rec.next_countdown_date = False
  83. # Exemption have not a start and end time
  84. elif (bool(rec.temporary_exempt_start_date)
  85. != bool(rec.temporary_exempt_end_date)):
  86. rec.next_countdown_date = False
  87. else:
  88. date = rec.today
  89. next_countdown_date = False
  90. while not next_countdown_date:
  91. date = self._next_countdown_date(
  92. rec.irregular_start_date, date
  93. )
  94. # Check holidays
  95. if (
  96. rec.holiday_start_time and rec.holiday_end_time
  97. and date >= rec.holiday_start_time
  98. and date <= rec.holiday_end_time
  99. ):
  100. date = add_days_delta(date, 1)
  101. continue
  102. # Check temporary exemption
  103. if (
  104. rec.temporary_exempt_start_date
  105. and rec.temporary_exempt_end_date
  106. and date >= rec.temporary_exempt_start_date
  107. and date <= rec.temporary_exempt_end_date
  108. ):
  109. date = add_days_delta(date, 1)
  110. continue
  111. # Otherwise
  112. next_countdown_date = date
  113. rec.next_countdown_date = next_countdown_date
  114. #####################################
  115. # Status Change implementation #
  116. #####################################
  117. def _get_regular_status(self):
  118. self.ensure_one()
  119. counter_unsubscribe = int(self.env['ir.config_parameter'].sudo().get_param('regular_counter_to_unsubscribe', -4))
  120. alert_delay = int(self.env['ir.config_parameter'].sudo().get_param('alert_delay', 28))
  121. grace_delay = int(self.env['ir.config_parameter'].sudo().get_param('default_grace_delay', 10))
  122. ok = self.sr >= 0 and self.sc >= 0
  123. grace_delay = grace_delay + self.time_extension
  124. if (self.sr + self.sc) <= counter_unsubscribe or self.unsubscribed:
  125. return 'unsubscribed'
  126. # Check if exempted. Exempt end date is not required.
  127. if self.temporary_exempt_start_date and self.today >= self.temporary_exempt_start_date:
  128. if not self.temporary_exempt_end_date or self.today <= self.temporary_exempt_end_date:
  129. return 'exempted'
  130. # Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined
  131. if not ok and self.alert_start_time and self.extension_start_time and self.today <= add_days_delta(self.extension_start_time, grace_delay):
  132. return 'extension'
  133. if not ok and self.alert_start_time and self.extension_start_time and self.today > add_days_delta(self.extension_start_time, grace_delay):
  134. return 'suspended'
  135. if not ok and self.alert_start_time and self.today > add_days_delta(self.alert_start_time, alert_delay):
  136. return 'suspended'
  137. if (self.sr < 0) or (not ok and self.alert_start_time):
  138. return 'alert'
  139. if (
  140. self.holiday_start_time
  141. and self.holiday_end_time
  142. and self.today >= self.holiday_start_time
  143. and self.today <= self.holiday_end_time
  144. ):
  145. return 'holiday'
  146. elif ok or (not self.alert_start_time and self.sr >= 0):
  147. return 'ok'
  148. def _get_irregular_status(self):
  149. self.ensure_one()
  150. counter_unsubscribe = int(self.env['ir.config_parameter'].sudo().get_param('irregular_counter_to_unsubscribe', -3))
  151. alert_delay = int(self.env['ir.config_parameter'].sudo().get_param('alert_delay', 28))
  152. grace_delay = int(self.env['ir.config_parameter'].sudo().get_param('default_grace_delay', 10))
  153. ok = self.sr >= 0
  154. grace_delay = grace_delay + self.time_extension
  155. if self.sr <= counter_unsubscribe or self.unsubscribed:
  156. return 'unsubscribed'
  157. # Check if exempted. Exempt end date is not required.
  158. elif self.temporary_exempt_start_date and self.today >= self.temporary_exempt_start_date:
  159. if not self.temporary_exempt_end_date or self.today <= self.temporary_exempt_end_date:
  160. return 'exempted'
  161. # Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined
  162. elif not ok and self.alert_start_time and self.extension_start_time and self.today <= add_days_delta(self.extension_start_time, grace_delay):
  163. return 'extension'
  164. elif not ok and self.alert_start_time and self.extension_start_time and self.today > add_days_delta(self.extension_start_time, grace_delay):
  165. return 'suspended'
  166. elif not ok and self.alert_start_time and self.today > add_days_delta(self.alert_start_time, alert_delay):
  167. return 'suspended'
  168. elif (self.sr < 0) or (not ok and self.alert_start_time):
  169. return 'alert'
  170. elif (
  171. self.holiday_start_time
  172. and self.holiday_end_time
  173. and self.today >= self.holiday_start_time
  174. and self.today <= self.holiday_end_time
  175. ):
  176. return 'holiday'
  177. elif ok or (not self.alert_start_time and self.sr >= 0):
  178. return 'ok'
  179. def _state_change(self, new_state):
  180. self.ensure_one()
  181. if new_state == 'alert':
  182. self.write({'alert_start_time': self.today, 'extension_start_time': False, 'time_extension': 0})
  183. if new_state == 'ok':
  184. data = {'extension_start_time': False, 'time_extension': 0}
  185. data['alert_start_time'] = False
  186. self.write(data)
  187. if new_state == 'unsubscribed' or new_state == 'resigning':
  188. # Remove worker from task_templates
  189. self.cooperator_id.sudo().write(
  190. {'subscribed_shift_ids': [(5, 0, 0)]})
  191. # Remove worker from supercoop in task_templates
  192. task_tpls = self.env['beesdoo.shift.template'].search(
  193. [('super_coop_id', 'in', self.cooperator_id.user_ids.ids)]
  194. )
  195. task_tpls.write({'super_coop_id': False})
  196. # Remove worker for future tasks (remove also supercoop)
  197. self.env['beesdoo.shift.shift'].sudo().unsubscribe_from_today(
  198. [self.cooperator_id.id], now=fields.Datetime.now()
  199. )
  200. def _change_counter(self, data):
  201. """
  202. Call when a shift state is changed
  203. use data generated by _get_counter_date_state_change
  204. """
  205. self.sc += data.get('sc', 0)
  206. self.sr += data.get('sr', 0)
  207. self.irregular_absence_counter += data.get('irregular_absence_counter', 0)
  208. self.irregular_absence_date = data.get('irregular_absence_date', False)
  209. ###############################################
  210. ###### Irregular Cron implementation ##########
  211. ###############################################
  212. def _get_irregular_worker_domain(self, **kwargs):
  213. today = kwargs.get("today") or self.today
  214. return ['&',
  215. '&',
  216. '&',
  217. ('status', 'not in', ['unsubscribed', 'exempted']),
  218. ('working_mode', '=', 'irregular'),
  219. ('irregular_start_date', '!=', False),
  220. '|',
  221. '|', ('holiday_start_time', '=', False), ('holiday_end_time', '=', False),
  222. '|', ('holiday_start_time', '>', today), ('holiday_end_time', '<', today),
  223. ]
  224. def _change_irregular_counter(self):
  225. if self.sr > 0:
  226. self.sr -= 1
  227. elif self.alert_start_time:
  228. self.sr -= 1
  229. else:
  230. self.sr -= 2
  231. ##################################
  232. # Internal Implementation #
  233. ##################################
  234. def _next_countdown_date(self, irregular_start_date, today=False):
  235. """
  236. Return the next countdown date given irregular_start_date and
  237. today dates.
  238. This does not take holiday and other status into account.
  239. """
  240. today = today or fields.Date.today()
  241. delta = (today - irregular_start_date).days
  242. if not delta % self._period:
  243. return today
  244. return add_days_delta(today, self._period - (delta % self._period))
  245. class ResPartner(models.Model):
  246. _inherit = 'res.partner'
  247. """
  248. Override is_worker definition
  249. You need have subscribe to a A Share
  250. """
  251. is_worker = fields.Boolean(compute="_is_worker", search="_search_worker", readonly=True, related="")
  252. def _is_worker(self):
  253. for rec in self:
  254. rec.is_worker = rec.cooperator_type == 'share_a'
  255. def _search_worker(self, operator, value):
  256. if (operator == '=' and value) or (operator == '!=' and not value):
  257. return [('cooperator_type', '=', 'share_a')]
  258. else:
  259. return [('cooperator_type', '!=', 'share_a')]