diff --git a/beesdoo_shift/data/cron.xml b/beesdoo_shift/data/cron.xml index efcdccfc1..5b4485742 100644 --- a/beesdoo_shift/data/cron.xml +++ b/beesdoo_shift/data/cron.xml @@ -1,7 +1,7 @@ - Update Cooperatoor status base on the date + Update Cooperator status base on the date code model._set_today() diff --git a/beesdoo_shift/models/cooperative_status.py b/beesdoo_shift/models/cooperative_status.py index b83931ecb..66c6f0910 100644 --- a/beesdoo_shift/models/cooperative_status.py +++ b/beesdoo_shift/models/cooperative_status.py @@ -1,5 +1,5 @@ import logging -from datetime import timedelta +from datetime import datetime, timedelta from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError @@ -65,7 +65,7 @@ def _get_status(self): "are based on the current date", default=fields.Date.today, ) - cooperator_id = fields.Many2one("res.partner") + cooperator_id = fields.Many2one("res.partner") # todo rename to worker_id active = fields.Boolean(related="cooperator_id.active", store=True, index=True) info_session = fields.Boolean("Information Session ?") info_session_date = fields.Date("Information Session Date") @@ -113,7 +113,23 @@ def _get_status(self): irregular_absence_counter = fields.Integer() # TODO unsubscribe when reach -2 future_alert_date = fields.Date(compute="_compute_future_alert_date") next_countdown_date = fields.Date(compute="_compute_next_countdown_date") - + next_shift_id = fields.Many2one( + comodel_name="beesdoo.shift.shift", + string="Earliest Open Shift", + compute="_compute_next_shift", + store=True, + help="Earliest open shift the worker is subscribed to.", + ) + next_shift_date = fields.Datetime( + related="next_shift_id.start_time", + string="Next Shift Date", + store=True, + ) + is_subscribed_to_shift = fields.Boolean( + string="Subscribed before Alert Date", + compute="_compute_next_shift", + store=True, + ) temporary_exempt_reason_id = fields.Many2one( comodel_name="cooperative.exempt.reason", string="Temporary Exempt Reason", @@ -380,6 +396,50 @@ def _compute_next_countdown_date(self): for rec in self: rec.next_countdown_date = False + @api.multi + @api.depends( + "cooperator_id.shift_shift_ids", + "cooperator_id.shift_shift_ids.state", + "future_alert_date", + "today", + ) + def _compute_next_shift(self): + # avoid searching for shift in loop + cooperator_ids = self.mapped("cooperator_id").ids + # rather take earliest "open" (confirmed) shift + # in order to take into account partners for which + # the counter was not incremented (happens when passing to "done") + next_shifts = self.env["beesdoo.shift.shift"].search( + [("state", "=", "open"), ("worker_id", "in", cooperator_ids)], + order="worker_id, start_time", + ) + + next_shift_by_worker = {} + for shift in next_shifts: + # take first shift for each worker + next_shift_by_worker.setdefault(shift.worker_id.id, shift) + + # what happens when no future shift ? + for rec in self: + rec.next_shift_id = next_shift_by_worker.get(rec.cooperator_id.id) + + if not rec.next_shift_id: + rec.is_subscribed_to_shift = False + continue + + if not rec.future_alert_date: + rec.is_subscribed_to_shift = True + continue + + future_alert_date_time = datetime( + rec.future_alert_date.year, + rec.future_alert_date.month, + rec.future_alert_date.day, + ) + rec.is_subscribed_to_shift = ( + rec.next_shift_id.start_time < future_alert_date_time + ) + def _can_shop_status(self): """ return the list of status that give access diff --git a/beesdoo_shift/models/res_partner.py b/beesdoo_shift/models/res_partner.py index 64c2a5dc0..1938de9f1 100644 --- a/beesdoo_shift/models/res_partner.py +++ b/beesdoo_shift/models/res_partner.py @@ -18,6 +18,8 @@ class ResPartner(models.Model): compute="_compute_can_shop", store=True, ) + # todo implement as delegated inheritance ? + # resolve as part of migration to OCA cooperative_status_ids = fields.One2many( string="Cooperative Statuses", comodel_name="cooperative.status", @@ -64,8 +66,23 @@ class ResPartner(models.Model): subscribed_shift_ids = fields.Many2many( comodel_name="beesdoo.shift.template", readonly=True ) - shift_task_ids = fields.One2many( - "beesdoo.shift.shift", "worker_id", string="Shifts" + shift_shift_ids = fields.One2many( + comodel_name="beesdoo.shift.shift", + inverse_name="worker_id", + string="Shifts", + help="All the shifts the worker is subscribed to.", + ) + next_shift_id = fields.Many2one( + related="cooperative_status_ids.next_shift_id", + store=True, + ) + is_subscribed_to_shift = fields.Boolean( + related="cooperative_status_ids.is_subscribed_to_shift", + store=True, + ) + next_shift_date = fields.Datetime( + related="cooperative_status_ids.next_shift_date", + store=True, ) @api.depends("cooperative_status_ids") diff --git a/beesdoo_shift/models/task.py b/beesdoo_shift/models/task.py index 9106fbb20..050c7a2d4 100644 --- a/beesdoo_shift/models/task.py +++ b/beesdoo_shift/models/task.py @@ -9,9 +9,7 @@ class Task(models.Model): _name = "beesdoo.shift.shift" - _inherit = ["mail.thread"] - _order = "start_time asc" ################################## diff --git a/beesdoo_shift/tests/test_beesdoo_shift.py b/beesdoo_shift/tests/test_beesdoo_shift.py index bf6ea8d01..91a254cce 100644 --- a/beesdoo_shift/tests/test_beesdoo_shift.py +++ b/beesdoo_shift/tests/test_beesdoo_shift.py @@ -20,6 +20,9 @@ def setUp(self): self.user_admin = self.env.ref("base.user_root") self.worker_regular_1 = self.env.ref("beesdoo_shift.res_partner_worker_1_demo") + self.worker_irregular_2 = self.env.ref( + "beesdoo_shift.res_partner_worker_2_demo" + ) self.worker_regular_3 = self.env.ref("beesdoo_shift.res_partner_worker_3_demo") self.worker_regular_5 = self.env.ref("beesdoo_shift.res_partner_worker_5_demo") self.worker_regular_6 = self.env.ref("beesdoo_shift.res_partner_worker_6_demo") @@ -421,3 +424,56 @@ def test_change_worker_temporary_exemption_2(self): ) exemption_wiz.exempt() self.assertEqual(self._count_number_of_shift(self.worker_regular_1), 4) + + def test_irregular_worker_subscribed_to_shift_before_alert(self): + self._generate_shifts(days=1, nb=2) + self.assertFalse(self.worker_irregular_2.cooperative_status_ids.next_shift_id) + + some_empty_shift = self.shift_model.search( + [("start_time", ">=", datetime.now()), ("worker_id", "=", False)], + limit=1, + ) + + some_empty_shift.worker_id = self.worker_irregular_2 + self.assertEqual( + self.worker_irregular_2.cooperative_status_ids.next_shift_id, + some_empty_shift, + ) + + some_empty_shift.worker_id = False + self.assertFalse(self.worker_irregular_2.cooperative_status_ids.next_shift_id) + + def test_unsubscribe_worker_from_task_template_computes_next_shift(self): + self._generate_shifts(days=1, nb=2) + now = datetime.now() + # Check that initialisation works well + next_shift = self.shift_model.search( + [ + ("start_time", ">=", now), + ("worker_id", "=", self.worker_regular_1.id), + ("task_template_id", "=", self.task_template_1.id), + ] + ) + self.assertEqual( + self.worker_regular_1.cooperative_status_ids.next_shift_id, + next_shift, + ) + + # Unsubscribe a worker from the task template + self.task_template_1.worker_ids -= self.worker_regular_1 + + self.assertFalse(self.worker_regular_1.cooperative_status_ids.next_shift_id) + + # Subscribe a worker from the task template + self.task_template_1.worker_ids += self.worker_regular_1 + next_shift = self.shift_model.search( + [ + ("start_time", ">=", now), + ("worker_id", "=", self.worker_regular_1.id), + ("task_template_id", "=", self.task_template_1.id), + ] + ) + self.assertEqual( + self.worker_regular_1.cooperative_status_ids.next_shift_id, + next_shift, + ) diff --git a/beesdoo_shift/views/cooperative_status.xml b/beesdoo_shift/views/cooperative_status.xml index a037486cf..c54d803fc 100644 --- a/beesdoo_shift/views/cooperative_status.xml +++ b/beesdoo_shift/views/cooperative_status.xml @@ -104,7 +104,7 @@ - + @@ -151,6 +151,8 @@ + + +