From 2aadff1bde84b5ab04c476a9fbd9cef3d0731ccf Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Mon, 20 Nov 2017 00:08:36 +0100 Subject: [PATCH] [ADD] Implement status management for irregular worker --- beesdoo_shift/data/cron.xml | 12 ++ beesdoo_shift/models/cooperative_status.py | 153 +++++++++++++++++---- beesdoo_shift/models/task.py | 78 +++++++---- beesdoo_shift/security/ir.model.access.csv | 2 + beesdoo_shift/views/cooperative_status.xml | 38 ++++- beesdoo_shift/views/task.xml | 1 + beesdoo_shift/wizard/subscribe.py | 12 +- beesdoo_shift/wizard/subscribe.xml | 1 + 8 files changed, 236 insertions(+), 61 deletions(-) diff --git a/beesdoo_shift/data/cron.xml b/beesdoo_shift/data/cron.xml index 040f9f7..a67f050 100644 --- a/beesdoo_shift/data/cron.xml +++ b/beesdoo_shift/data/cron.xml @@ -23,5 +23,17 @@ () + + + Compute Shift Counter + 4 + hours + -1 + + cooperative.status + _cron_compute_counter_irregular + () + + \ No newline at end of file diff --git a/beesdoo_shift/models/cooperative_status.py b/beesdoo_shift/models/cooperative_status.py index 886e306..48b171a 100644 --- a/beesdoo_shift/models/cooperative_status.py +++ b/beesdoo_shift/models/cooperative_status.py @@ -2,7 +2,11 @@ from openerp import models, fields, api, _ from openerp.exceptions import ValidationError -from datetime import timedelta +from datetime import timedelta, datetime +import logging +from openerp.osv.fields import related + +_logger = logging.getLogger(__name__) def add_days_delta(date_from, days_delta): if not date_from: @@ -65,49 +69,97 @@ class CooperativeStatus(models.Model): history_ids = fields.One2many('cooperative.status.history', 'status_id', readonly=True) unsubscribed = fields.Boolean(default=False, help="Manually unsubscribed") + #Specific to irregular + irregular_start_date = fields.Date() #TODO migration script + irregular_absence_date = fields.Date() + irregular_absence_counter = fields.Integer() #TODO unsubscribe when reach -2 - @api.depends('today', 'sr', 'sc', 'holiday_end_time', 'holiday_start_time', 'time_extension', 'alert_start_time', 'extension_start_time', 'unsubscribed') + @api.depends('today', 'sr', 'sc', 'holiday_end_time', + 'holiday_start_time', 'time_extension', + 'alert_start_time', 'extension_start_time', + 'unsubscribed', 'irregular_absence_date', + 'irregular_absence_counter') def _compute_status(self): alert_delay = int(self.env['ir.config_parameter'].get_param('alert_delay', 28)) grace_delay = int(self.env['ir.config_parameter'].get_param('default_grace_delay', 10)) update = int(self.env['ir.config_parameter'].get_param('always_update', False)) print update for rec in self: - if update: + if update or not self.today: rec.status = 'ok' rec.can_shop = True continue - ok = rec.sr >= 0 and rec.sc >= 0 - grace_delay = grace_delay + rec.time_extension - - if rec.sr < -1 or rec.unsubscribed: - rec.status = 'unsubscribed' - rec.can_shop = False - - #Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined - elif not ok and rec.alert_start_time and rec.extension_start_time and rec.today <= add_days_delta(rec.extension_start_time, grace_delay): - rec.status = 'extension' - rec.can_shop = True - elif not ok and rec.alert_start_time and rec.extension_start_time and rec.today > add_days_delta(rec.extension_start_time, grace_delay): - rec.status = 'suspended' - rec.can_shop = False - elif not ok and rec.alert_start_time and rec.today > add_days_delta(rec.alert_start_time, alert_delay): - rec.status = 'suspended' - rec.can_shop = False - elif (rec.sr < 0) or (not ok and rec.alert_start_time): - rec.status = 'alert' - rec.can_shop = True - - #Check for holidays; Can be in holidays even in alert or other mode ? - elif rec.today >= rec.holiday_start_time and rec.today <= rec.holiday_end_time: - rec.status = 'holiday' - rec.can_shop = True - elif ok or (not rec.alert_start_time and rec.sr >= 0): + if rec.working_mode == 'regular': + rec._set_regular_status(grace_delay, alert_delay) + elif rec.working_mode == 'irregular': + rec._set_irregular_status(grace_delay, alert_delay) + elif rec.working_mode == 'exempt': rec.status = 'ok' rec.can_shop = True + def _set_regular_status(self, grace_delay, alert_delay): + self.ensure_one() + ok = self.sr >= 0 and self.sc >= 0 + grace_delay = grace_delay + self.time_extension + + if self.sr < -1 or self.unsubscribed: + self.status = 'unsubscribed' + self.can_shop = False + + #Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined + 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): + self.status = 'extension' + self.can_shop = True + 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): + self.status = 'suspended' + self.can_shop = False + elif not ok and self.alert_start_time and self.today > add_days_delta(self.alert_start_time, alert_delay): + self.status = 'suspended' + self.can_shop = False + elif (self.sr < 0) or (not ok and self.alert_start_time): + self.status = 'alert' + self.can_shop = True + + #Check for holidays; Can be in holidays even in alert or other mode ? + elif self.today >= self.holiday_start_time and self.today <= self.holiday_end_time: + self.status = 'holiday' + self.can_shop = True + elif ok or (not self.alert_start_time and self.sr >= 0): + self.status = 'ok' + self.can_shop = True + + def _set_irregular_status(self, grace_delay, alert_delay): + self.ensure_one() + ok = self.sr >= 0 + grace_delay = grace_delay + self.time_extension + print add_days_delta(self.extension_start_time, grace_delay) + if (not ok and self.irregular_absence_date and self.today > add_days_delta(self.irregular_absence_date, alert_delay * 2)) \ + or self.unsubscribed or self.irregular_absence_counter <= -2: + self.status = 'unsubscribed' + self.can_shop = False + #Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined + 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): + self.status = 'extension' + self.can_shop = True + 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): + self.status = 'suspended' + self.can_shop = False + elif not ok and self.alert_start_time and self.today > add_days_delta(self.alert_start_time, alert_delay): + self.status = 'suspended' + self.can_shop = False + elif (self.sr < 0) or (not ok and self.alert_start_time): + self.status = 'alert' + self.can_shop = True + + #Check for holidays; Can be in holidays even in alert or other mode ? + elif self.today >= self.holiday_start_time and self.today <= self.holiday_end_time: + self.status = 'holiday' + self.can_shop = True + elif ok or (not self.alert_start_time and self.sr >= 0): + self.status = 'ok' + self.can_shop = True @api.multi def write(self, vals): @@ -137,11 +189,14 @@ class CooperativeStatus(models.Model): self.write({'alert_start_time': False, 'extension_start_time': False, 'time_extension': 0}) if new_state == 'unsubscribed': self.cooperator_id.sudo().write({'subscribed_shift_ids' : [(5,0,0)]}) + #TODO: Add one day othertwise unsubscribed from the shift you were absent self.env['beesdoo.shift.shift'].sudo().unsubscribe_from_today([self.cooperator_id.id], today=self.today) def _change_counter(self, data): self.sc += data.get('sc', 0) self.sr += data.get('sr', 0) + self.irregular_absence_counter += data.get('irregular_absence_counter', 0) + self.irregular_absence_date = data.get('irregular_absence_date', False) @api.multi def _write(self, vals): @@ -181,7 +236,45 @@ class CooperativeStatus(models.Model): def clear_history(self): self.ensure_one() self.history_ids.unlink() - + + @api.model + def _cron_compute_counter_irregular(self, today=False): + today = today or fields.Date.today() + journal = self.env['beesdoo.shift.journal'].search([('date', '=', today)]) + if not journal: + journal = self.env['beesdoo.shift.journal'].create({'date': today}) + + irregular = self.search([('status', '!=', 'unsubscribed'), ('working_mode', '=', 'irregular'), ('irregular_start_date', '!=', False)]) + today_date = fields.Date.from_string(today) + for status in irregular: + delta = (today_date - fields.Date.from_string(status.irregular_start_date)).days + if delta and delta % 28 == 0 and status not in journal.line_ids: #TODO use system parameter for 28 + if status.sr > 0: + status.sr -= 1 + else: + status.sr -= 2 + journal.line_ids |= status + + +class ShiftCronJournal(models.Model): + _name = 'beesdoo.shift.journal' + _order = 'date desc' + _rec_name = 'date' + + date = fields.Date() + line_ids = fields.Many2many('cooperative.status') + + _sql_constraints = [ + ('one_entry_per_day', 'unique (date)', _('You can only create one journal per day')), + ] + + @api.multi + def run(self): + self.ensure_one() + if not self.user_has_groups('beesdoo_shift.group_cooperative_admin'): + raise ValidationError(_("You don't have the access to perform this action")) + self.sudo().env['cooperative.status']._cron_compute_counter_irregular(today=self.date) + class ResPartner(models.Model): _inherit = 'res.partner' diff --git a/beesdoo_shift/models/task.py b/beesdoo_shift/models/task.py index 9deb853..6058c2b 100644 --- a/beesdoo_shift/models/task.py +++ b/beesdoo_shift/models/task.py @@ -87,11 +87,14 @@ class Task(models.Model): return super(Task, self).write(vals) def _set_revert_info(self, data, status): - data = { + data_new = { 'status_id': status.id, - 'data' : {k: data[k] * -1 for k in data.keys()} + 'data' : {k: data.get(k, 0) * -1 for k in ['sr', 'sc', 'irregular_absence_counter']} } - self.write({'revert_info': json.dumps(data)}) + if data.get('irregular_absence_date'): + data_new['data']['irregular_absence_date'] = False + + self.write({'revert_info': json.dumps(data_new)}) def _revert(self): if not self.revert_info: @@ -107,35 +110,54 @@ class Task(models.Model): self.ensure_one() self._revert() update = int(self.env['ir.config_parameter'].get_param('always_update', False)) - if not (self.worker_id or self.replaced_id) or update: - return + new_stage = self.env['beesdoo.shift.stage'].browse(new_stage) - - if not self.replaced_id: #No replacement case - status = self.worker_id.cooperative_status_ids[0] - else: - status = self.replaced_id.cooperative_status_ids[0] - data = {} - if new_stage == self.env.ref('beesdoo_shift.done') and self.is_regular: - pass - if new_stage == self.env.ref('beesdoo_shift.done') and not self.is_regular: - if status.sr < 0: - data['sr'] = 1 - elif status.sc < 0: - data['sc'] = 1 + DONE = self.env.ref('beesdoo_shift.done') + ABSENT = self.env.ref('beesdoo_shift.absent') + EXCUSED = self.env.ref('beesdoo_shift.excused') + NECESSITY = self.env.ref('beesdoo_shift.excused_necessity') + + if not (self.worker_id or self.replaced_id) and new_stage in (DONE, ABSENT, EXCUSED, NECESSITY): + raise UserError(_("You cannot change to the status %s if the is no worker defined on the shift") % new_stage.name) + + if update or not (self.worker_id or self.replaced_id): + return + + if self.worker_id.working_mode == 'regular': + if not self.replaced_id: #No replacement case + status = self.worker_id.cooperative_status_ids[0] else: + status = self.replaced_id.cooperative_status_ids[0] + + if new_stage == DONE and not self.is_regular: + if status.sr < 0: + data['sr'] = 1 + elif status.sc < 0: + data['sc'] = 1 + else: + data['sr'] = 1 + + if new_stage == ABSENT and not self.replaced_id: + data['sr'] = - 1 + if status.sr <= 0: + data['sc'] = -1 + if new_stage == ABSENT and self.replaced_id: + data['sr'] = -1 + + if new_stage == EXCUSED: + data['sr'] = -1 + + elif self.worker_id.working_mode == 'irregular': + status = self.worker_id.cooperative_status_ids[0] + if new_stage == DONE or new_stage == NECESSITY: data['sr'] = 1 - - if new_stage == self.env.ref('beesdoo_shift.absent') and not self.replaced_id: - data['sr'] = - 1 - if status.sr <= 0: - data['sc'] = -1 - if new_stage == self.env.ref('beesdoo_shift.absent') and self.replaced_id: - data['sr'] = -1 - - if new_stage == self.env.ref('beesdoo_shift.excused'): - data['sr'] = -1 + data['irregular_absence_date'] = False + data['irregular_absence_counter'] = 1 if status.irregular_absence_counter < 0 else 0 + if new_stage == ABSENT or new_stage == EXCUSED: + data['sr'] = -2 + data['irregular_absence_date'] = self.start_time[:10] + data['irregular_absence_counter'] = -1 status.sudo()._change_counter(data) self._set_revert_info(data, status) diff --git a/beesdoo_shift/security/ir.model.access.csv b/beesdoo_shift/security/ir.model.access.csv index 3ff2efe..0d8ddb7 100644 --- a/beesdoo_shift/security/ir.model.access.csv +++ b/beesdoo_shift/security/ir.model.access.csv @@ -17,3 +17,5 @@ all_config_coopplanning_task,Attendance Edit Shift,model_beesdoo_shift_shift,gro exempt_reason_read_all,Exempt Reason Read all ,beesdoo_shift.model_cooperative_exempt_reason,,1,0,0,0 exempt_reason,Exempt Reason Admin,beesdoo_shift.model_cooperative_exempt_reason,beesdoo_shift.group_cooperative_admin,1,1,1,1 history_read_all,History Read All,beesdoo_shift.model_cooperative_status_history,,1,0,0,0 +access_beesdoo_shift_journal,access_beesdoo_shift_journal,model_beesdoo_shift_journal,beesdoo_shift.group_cooperative_admin,1,0,1,1 +access_beesdoo_shift_journal_line,access_beesdoo_shift_journal_line,model_beesdoo_shift_journal_line,beesdoo_shift.group_cooperative_admin,1,0,0,0 diff --git a/beesdoo_shift/views/cooperative_status.xml b/beesdoo_shift/views/cooperative_status.xml index f5c3f02..6e8a1aa 100644 --- a/beesdoo_shift/views/cooperative_status.xml +++ b/beesdoo_shift/views/cooperative_status.xml @@ -63,15 +63,19 @@ + + + + - + @@ -119,6 +123,29 @@ + + + Journal Form View + beesdoo.shift.journal + +
+
+
+ + + + + + + + + + + + +
+
Cooperator Status @@ -143,6 +170,15 @@ sequence="1" /> + + + Counter Journal + beesdoo.shift.journal + tree,form + + + diff --git a/beesdoo_shift/views/task.xml b/beesdoo_shift/views/task.xml index 2a5b45a..7335464 100644 --- a/beesdoo_shift/views/task.xml +++ b/beesdoo_shift/views/task.xml @@ -98,6 +98,7 @@ + diff --git a/beesdoo_shift/wizard/subscribe.py b/beesdoo_shift/wizard/subscribe.py index c910599..2040a57 100644 --- a/beesdoo_shift/wizard/subscribe.py +++ b/beesdoo_shift/wizard/subscribe.py @@ -33,7 +33,8 @@ class Subscribe(models.TransientModel): return self.env['res.partner'].browse(self._context.get('active_id')).working_mode def _get_reset_counter_default(self): - return self.env['res.partner'].browse(self._context.get('active_id')).state == 'unsubscribed' + partner = self.env['res.partner'].browse(self._context.get('active_id')) + return partner.state == 'unsubscribed' and partner.working_mode == 'regular' info_session = fields.Boolean(string="Followed an information session", default=True) info_session_date = fields.Date(string="Date of information session", default=_get_date) @@ -50,6 +51,7 @@ class Subscribe(models.TransientModel): reset_counter = fields.Boolean(default=_get_reset_counter_default) reset_compensation_counter = fields.Boolean(default=False) unsubscribed = fields.Boolean(default=False, string="Are you sure to unsubscribe this cooperator") + irregular_start_date = fields.Date(string="Start Date", default=fields.Date.today) @@ -80,6 +82,7 @@ class Subscribe(models.TransientModel): if self.working_mode != 'regular': #Remove existing shift then subscribe to the new shift self.cooperator_id.sudo().write({'subscribed_shift_ids' : [(5,)]}) + data = { 'info_session' : self.info_session, @@ -88,7 +91,10 @@ class Subscribe(models.TransientModel): 'exempt_reason_id' : self.exempt_reason_id.id, 'super' : self.super, 'cooperator_id': self.cooperator_id.id, - 'unsubscribed': False + 'unsubscribed': False, + 'irregular_start_date': self.irregular_start_date, + 'irregular_absence_date': False, + 'irregular_absence_counter': 0, } if self.reset_counter: data['sr'] = 0 @@ -103,3 +109,5 @@ class Subscribe(models.TransientModel): status_id.sudo().write(data) else: self.env['cooperative.status'].sudo().create(data) + + diff --git a/beesdoo_shift/wizard/subscribe.xml b/beesdoo_shift/wizard/subscribe.xml index 14f4633..5c6dcca 100644 --- a/beesdoo_shift/wizard/subscribe.xml +++ b/beesdoo_shift/wizard/subscribe.xml @@ -15,6 +15,7 @@ +