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.

365 lines
13 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. import logging
  2. from datetime import datetime, timedelta
  3. from odoo import _, api, fields, models
  4. from odoo.exceptions import UserError, ValidationError
  5. from odoo.addons.beesdoo_shift.models.cooperative_status import add_days_delta
  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(
  17. "today",
  18. "irregular_start_date",
  19. "sr",
  20. "holiday_start_time",
  21. "holiday_end_time",
  22. "temporary_exempt_start_date",
  23. "temporary_exempt_end_date",
  24. )
  25. def _compute_future_alert_date(self):
  26. """Compute date before which the worker is up to date"""
  27. for rec in self:
  28. # Only for irregular worker
  29. if (
  30. rec.working_mode != "irregular"
  31. and not rec.irregular_start_date
  32. ):
  33. rec.future_alert_date = False
  34. # Alert start time already set
  35. elif rec.alert_start_time:
  36. rec.future_alert_date = False
  37. # Holidays are not set properly
  38. elif bool(rec.holiday_start_time) != bool(rec.holiday_end_time):
  39. rec.future_alert_date = False
  40. # Exemption have not a start and end time
  41. elif bool(rec.temporary_exempt_start_date) != bool(
  42. rec.temporary_exempt_end_date
  43. ):
  44. rec.future_alert_date = False
  45. else:
  46. date = rec.today
  47. counter = rec.sr
  48. # Simulate the countdown
  49. while counter > 0:
  50. date = self._next_countdown_date(
  51. rec.irregular_start_date, date
  52. )
  53. # Check holidays
  54. if (
  55. rec.holiday_start_time
  56. and rec.holiday_end_time
  57. and date >= rec.holiday_start_time
  58. and date <= rec.holiday_end_time
  59. ):
  60. date = add_days_delta(date, 1)
  61. continue
  62. # Check temporary exemption
  63. if (
  64. rec.temporary_exempt_start_date
  65. and rec.temporary_exempt_end_date
  66. and date >= rec.temporary_exempt_start_date
  67. and date <= rec.temporary_exempt_end_date
  68. ):
  69. date = add_days_delta(date, 1)
  70. continue
  71. # Otherwise
  72. date = add_days_delta(date, 1)
  73. counter -= 1
  74. rec.future_alert_date = self._next_countdown_date(
  75. rec.irregular_start_date, date
  76. )
  77. @api.depends(
  78. "today",
  79. "irregular_start_date",
  80. "holiday_start_time",
  81. "holiday_end_time",
  82. "temporary_exempt_start_date",
  83. "temporary_exempt_end_date",
  84. )
  85. def _compute_next_countdown_date(self):
  86. """
  87. Compute the following countdown date. This date is the date when
  88. the worker will see his counter changed du to the cron. This
  89. date is like the birthday date of the worker that occurred each
  90. PERIOD.
  91. """
  92. for rec in self:
  93. # Only for irregular worker
  94. if (
  95. rec.working_mode != "irregular"
  96. and not rec.irregular_start_date
  97. ):
  98. rec.next_countdown_date = False
  99. # Holidays are not set properly
  100. elif bool(rec.holiday_start_time) != bool(rec.holiday_end_time):
  101. rec.next_countdown_date = False
  102. # Exemption have not a start and end time
  103. elif bool(rec.temporary_exempt_start_date) != bool(
  104. rec.temporary_exempt_end_date
  105. ):
  106. rec.next_countdown_date = False
  107. else:
  108. date = rec.today
  109. next_countdown_date = False
  110. while not next_countdown_date:
  111. date = self._next_countdown_date(
  112. rec.irregular_start_date, date
  113. )
  114. # Check holidays
  115. if (
  116. rec.holiday_start_time
  117. and rec.holiday_end_time
  118. and date >= rec.holiday_start_time
  119. and date <= rec.holiday_end_time
  120. ):
  121. date = add_days_delta(date, 1)
  122. continue
  123. # Check temporary exemption
  124. if (
  125. rec.temporary_exempt_start_date
  126. and rec.temporary_exempt_end_date
  127. and date >= rec.temporary_exempt_start_date
  128. and date <= rec.temporary_exempt_end_date
  129. ):
  130. date = add_days_delta(date, 1)
  131. continue
  132. # Otherwise
  133. next_countdown_date = date
  134. rec.next_countdown_date = next_countdown_date
  135. #####################################
  136. # Status Change implementation #
  137. #####################################
  138. def _get_regular_status(self):
  139. self.ensure_one()
  140. counter_unsubscribe = int(
  141. self.env["ir.config_parameter"]
  142. .sudo()
  143. .get_param("regular_counter_to_unsubscribe", -4)
  144. )
  145. alert_delay = int(
  146. self.env["ir.config_parameter"].sudo().get_param("alert_delay", 28)
  147. )
  148. grace_delay = int(
  149. self.env["ir.config_parameter"]
  150. .sudo()
  151. .get_param("default_grace_delay", 10)
  152. )
  153. ok = self.sr >= 0 and self.sc >= 0
  154. grace_delay = grace_delay + self.time_extension
  155. if (self.sr + self.sc) <= counter_unsubscribe or self.unsubscribed:
  156. return "unsubscribed"
  157. # Check if exempted. Exempt end date is not required.
  158. if (
  159. self.temporary_exempt_start_date
  160. and self.today >= self.temporary_exempt_start_date
  161. ):
  162. if (
  163. not self.temporary_exempt_end_date
  164. or self.today <= self.temporary_exempt_end_date
  165. ):
  166. return "exempted"
  167. # Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined
  168. if (
  169. not ok
  170. and self.alert_start_time
  171. and self.extension_start_time
  172. and self.today
  173. <= add_days_delta(self.extension_start_time, grace_delay)
  174. ):
  175. return "extension"
  176. if (
  177. not ok
  178. and self.alert_start_time
  179. and self.extension_start_time
  180. and self.today
  181. > add_days_delta(self.extension_start_time, grace_delay)
  182. ):
  183. return "suspended"
  184. if (
  185. not ok
  186. and self.alert_start_time
  187. and self.today > add_days_delta(self.alert_start_time, alert_delay)
  188. ):
  189. return "suspended"
  190. if (self.sr < 0) or (not ok and self.alert_start_time):
  191. return "alert"
  192. if (
  193. self.holiday_start_time
  194. and self.holiday_end_time
  195. and self.today >= self.holiday_start_time
  196. and self.today <= self.holiday_end_time
  197. ):
  198. return "holiday"
  199. elif ok or (not self.alert_start_time and self.sr >= 0):
  200. return "ok"
  201. def _get_irregular_status(self):
  202. self.ensure_one()
  203. counter_unsubscribe = int(
  204. self.env["ir.config_parameter"]
  205. .sudo()
  206. .get_param("irregular_counter_to_unsubscribe", -3)
  207. )
  208. alert_delay = int(
  209. self.env["ir.config_parameter"].sudo().get_param("alert_delay", 28)
  210. )
  211. grace_delay = int(
  212. self.env["ir.config_parameter"]
  213. .sudo()
  214. .get_param("default_grace_delay", 10)
  215. )
  216. ok = self.sr >= 0
  217. grace_delay = grace_delay + self.time_extension
  218. if self.sr <= counter_unsubscribe or self.unsubscribed:
  219. return "unsubscribed"
  220. # Check if exempted. Exempt end date is not required.
  221. elif (
  222. self.temporary_exempt_start_date
  223. and self.today >= self.temporary_exempt_start_date
  224. ):
  225. if (
  226. not self.temporary_exempt_end_date
  227. or self.today <= self.temporary_exempt_end_date
  228. ):
  229. return "exempted"
  230. # Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined
  231. elif (
  232. not ok
  233. and self.alert_start_time
  234. and self.extension_start_time
  235. and self.today
  236. <= add_days_delta(self.extension_start_time, grace_delay)
  237. ):
  238. return "extension"
  239. elif (
  240. not ok
  241. and self.alert_start_time
  242. and self.extension_start_time
  243. and self.today
  244. > add_days_delta(self.extension_start_time, grace_delay)
  245. ):
  246. return "suspended"
  247. elif (
  248. not ok
  249. and self.alert_start_time
  250. and self.today > add_days_delta(self.alert_start_time, alert_delay)
  251. ):
  252. return "suspended"
  253. elif (self.sr < 0) or (not ok and self.alert_start_time):
  254. return "alert"
  255. elif (
  256. self.holiday_start_time
  257. and self.holiday_end_time
  258. and self.today >= self.holiday_start_time
  259. and self.today <= self.holiday_end_time
  260. ):
  261. return "holiday"
  262. elif ok or (not self.alert_start_time and self.sr >= 0):
  263. return "ok"
  264. def _state_change(self, new_state):
  265. self.ensure_one()
  266. if new_state == "alert":
  267. self.write(
  268. {
  269. "alert_start_time": self.today,
  270. "extension_start_time": False,
  271. "time_extension": 0,
  272. }
  273. )
  274. if new_state == "ok":
  275. data = {"extension_start_time": False, "time_extension": 0}
  276. data["alert_start_time"] = False
  277. self.write(data)
  278. if new_state == "unsubscribed" or new_state == "resigning":
  279. # Remove worker from task_templates
  280. self.cooperator_id.sudo().write(
  281. {"subscribed_shift_ids": [(5, 0, 0)]}
  282. )
  283. # Remove worker from supercoop in task_templates
  284. task_tpls = self.env["beesdoo.shift.template"].search(
  285. [("super_coop_id", "in", self.cooperator_id.user_ids.ids)]
  286. )
  287. task_tpls.write({"super_coop_id": False})
  288. # Remove worker for future tasks (remove also supercoop)
  289. self.env["beesdoo.shift.shift"].sudo().unsubscribe_from_today(
  290. [self.cooperator_id.id], now=fields.Datetime.now()
  291. )
  292. def _change_counter(self, data):
  293. """
  294. Call when a shift state is changed
  295. use data generated by _get_counter_date_state_change
  296. """
  297. self.sc += data.get("sc", 0)
  298. self.sr += data.get("sr", 0)
  299. self.irregular_absence_counter += data.get(
  300. "irregular_absence_counter", 0
  301. )
  302. self.irregular_absence_date = data.get("irregular_absence_date", False)
  303. ###############################################
  304. ###### Irregular Cron implementation ##########
  305. ###############################################
  306. def _get_irregular_worker_domain(self, **kwargs):
  307. today = kwargs.get("today") or self.today
  308. return [
  309. "&",
  310. "&",
  311. "&",
  312. ("status", "not in", ["unsubscribed", "exempted"]),
  313. ("working_mode", "=", "irregular"),
  314. ("irregular_start_date", "!=", False),
  315. "|",
  316. "|",
  317. ("holiday_start_time", "=", False),
  318. ("holiday_end_time", "=", False),
  319. "|",
  320. ("holiday_start_time", ">", today),
  321. ("holiday_end_time", "<", today),
  322. ]
  323. def _change_irregular_counter(self):
  324. if self.sr > 0:
  325. self.sr -= 1
  326. elif self.alert_start_time:
  327. self.sr -= 1
  328. else:
  329. self.sr -= 2
  330. ##################################
  331. # Internal Implementation #
  332. ##################################
  333. def _next_countdown_date(self, irregular_start_date, today=False):
  334. """
  335. Return the next countdown date given irregular_start_date and
  336. today dates.
  337. This does not take holiday and other status into account.
  338. """
  339. today = today or fields.Date.today()
  340. delta = (today - irregular_start_date).days
  341. if not delta % self._period:
  342. return today
  343. return add_days_delta(today, self._period - (delta % self._period))