Browse Source

[ADD] Implement status management for irregular worker

pull/105/head
Thibault Francois 7 years ago
committed by Elouan
parent
commit
2aadff1bde
  1. 12
      beesdoo_shift/data/cron.xml
  2. 151
      beesdoo_shift/models/cooperative_status.py
  3. 76
      beesdoo_shift/models/task.py
  4. 2
      beesdoo_shift/security/ir.model.access.csv
  5. 38
      beesdoo_shift/views/cooperative_status.xml
  6. 1
      beesdoo_shift/views/task.xml
  7. 12
      beesdoo_shift/wizard/subscribe.py
  8. 1
      beesdoo_shift/wizard/subscribe.xml

12
beesdoo_shift/data/cron.xml

@ -23,5 +23,17 @@
<field name="args">()</field> <field name="args">()</field>
<field name="active" eval="False" /> <field name="active" eval="False" />
</record> </record>
<record id="ir_cron_compute_shift_counter" model="ir.cron">
<field name="name">Compute Shift Counter</field>
<field name="interval_number">4</field>
<field name="interval_type">hours</field>
<field name="numbercall">-1</field>
<field name="doall" eval="True" />
<field name="model">cooperative.status</field>
<field name="function">_cron_compute_counter_irregular</field>
<field name="args">()</field>
<field name="active" eval="False" />
</record>
</data> </data>
</odoo> </odoo>

151
beesdoo_shift/models/cooperative_status.py

@ -2,7 +2,11 @@
from openerp import models, fields, api, _ from openerp import models, fields, api, _
from openerp.exceptions import ValidationError 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): def add_days_delta(date_from, days_delta):
if not date_from: if not date_from:
@ -65,49 +69,97 @@ class CooperativeStatus(models.Model):
history_ids = fields.One2many('cooperative.status.history', 'status_id', readonly=True) history_ids = fields.One2many('cooperative.status.history', 'status_id', readonly=True)
unsubscribed = fields.Boolean(default=False, help="Manually unsubscribed") 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): def _compute_status(self):
alert_delay = int(self.env['ir.config_parameter'].get_param('alert_delay', 28)) 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)) 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)) update = int(self.env['ir.config_parameter'].get_param('always_update', False))
print update print update
for rec in self: for rec in self:
if update:
if update or not self.today:
rec.status = 'ok' rec.status = 'ok'
rec.can_shop = True rec.can_shop = True
continue 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.status = 'ok'
rec.can_shop = True 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 @api.multi
def write(self, vals): 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}) self.write({'alert_start_time': False, 'extension_start_time': False, 'time_extension': 0})
if new_state == 'unsubscribed': if new_state == 'unsubscribed':
self.cooperator_id.sudo().write({'subscribed_shift_ids' : [(5,0,0)]}) 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) self.env['beesdoo.shift.shift'].sudo().unsubscribe_from_today([self.cooperator_id.id], today=self.today)
def _change_counter(self, data): def _change_counter(self, data):
self.sc += data.get('sc', 0) self.sc += data.get('sc', 0)
self.sr += data.get('sr', 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 @api.multi
def _write(self, vals): def _write(self, vals):
@ -182,6 +237,44 @@ class CooperativeStatus(models.Model):
self.ensure_one() self.ensure_one()
self.history_ids.unlink() 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): class ResPartner(models.Model):
_inherit = 'res.partner' _inherit = 'res.partner'

76
beesdoo_shift/models/task.py

@ -87,11 +87,14 @@ class Task(models.Model):
return super(Task, self).write(vals) return super(Task, self).write(vals)
def _set_revert_info(self, data, status): def _set_revert_info(self, data, status):
data = {
data_new = {
'status_id': status.id, '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): def _revert(self):
if not self.revert_info: if not self.revert_info:
@ -107,35 +110,54 @@ class Task(models.Model):
self.ensure_one() self.ensure_one()
self._revert() self._revert()
update = int(self.env['ir.config_parameter'].get_param('always_update', False)) 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) new_stage = self.env['beesdoo.shift.stage'].browse(new_stage)
data = {}
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.replaced_id: #No replacement case
status = self.worker_id.cooperative_status_ids[0]
else:
status = self.replaced_id.cooperative_status_ids[0]
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)
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
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: 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 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) status.sudo()._change_counter(data)
self._set_revert_info(data, status) self._set_revert_info(data, status)

2
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_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 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 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

38
beesdoo_shift/views/cooperative_status.xml

@ -63,15 +63,19 @@
<group> <group>
<group> <group>
<field name="cooperator_id" /> <field name="cooperator_id" />
<field name="super" />
<field name="working_mode" /> <field name="working_mode" />
<field name="irregular_start_date" attrs="{'invisible':[('working_mode', '!=', 'irregular')]}" />
<field name="irregular_absence_date" attrs="{'invisible':[('working_mode', '!=', 'irregular')]}" />
<field name="exempt_reason_id" attrs="{'invisible':[('working_mode', '!=', 'exempt')]}"/> <field name="exempt_reason_id" attrs="{'invisible':[('working_mode', '!=', 'exempt')]}"/>
<field name="super" />
</group> </group>
<group> <group>
<field name="info_session" /> <field name="info_session" />
<field name="info_session_date" /> <field name="info_session_date" />
<field name="sr" /> <field name="sr" />
<field name="sc" /> <field name="sc" />
<field name="irregular_absence_counter" attrs="{'invisible':[('working_mode', '!=', 'irregular')]}" />
<field name="unsubscribed" /> <field name="unsubscribed" />
<field name="can_shop" /> <field name="can_shop" />
</group> </group>
@ -120,6 +124,29 @@
</field> </field>
</record> </record>
<record model="ir.ui.view" id="journal_form_view">
<field name="name">Journal Form View</field>
<field name="model">beesdoo.shift.journal</field>
<field name="arch" type="xml">
<form>
<header>
<button name="run" string="Run again for this day" type="object" />
</header>
<group>
<group>
<field name="date" />
</group>
</group>
<separator string="Affected cooperator" />
<field name="line_ids" readonly="1">
<tree>
<field name="cooperator_id" />
</tree>
</field>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_coop_status"> <record model="ir.actions.act_window" id="action_coop_status">
<field name="name">Cooperator Status</field> <field name="name">Cooperator Status</field>
<field name="res_model">cooperative.status</field> <field name="res_model">cooperative.status</field>
@ -143,6 +170,15 @@
sequence="1" /> sequence="1" />
<menuitem name="Worker" id="menu_worker" parent="menu_worker_top" <menuitem name="Worker" id="menu_worker" parent="menu_worker_top"
action="action_worker" /> action="action_worker" />
<record model="ir.actions.act_window" id="action_journal">
<field name="name">Counter Journal</field>
<field name="res_model">beesdoo.shift.journal</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Counter Update Journal" id="menu_journal" parent="menu_status_top"
action="action_journal" groups="beesdoo_shift.group_cooperative_admin" />
</odoo> </odoo>

1
beesdoo_shift/views/task.xml

@ -98,6 +98,7 @@
<group> <group>
<field name="start_time" /> <field name="start_time" />
<field name="end_time" /> <field name="end_time" />
<field name="revert_info" invisible="0" />
</group> </group>
</group> </group>
</sheet> </sheet>

12
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 return self.env['res.partner'].browse(self._context.get('active_id')).working_mode
def _get_reset_counter_default(self): 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 = fields.Boolean(string="Followed an information session", default=True)
info_session_date = fields.Date(string="Date of information session", default=_get_date) 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_counter = fields.Boolean(default=_get_reset_counter_default)
reset_compensation_counter = fields.Boolean(default=False) reset_compensation_counter = fields.Boolean(default=False)
unsubscribed = fields.Boolean(default=False, string="Are you sure to unsubscribe this cooperator") 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)
@ -81,6 +83,7 @@ class Subscribe(models.TransientModel):
#Remove existing shift then subscribe to the new shift #Remove existing shift then subscribe to the new shift
self.cooperator_id.sudo().write({'subscribed_shift_ids' : [(5,)]}) self.cooperator_id.sudo().write({'subscribed_shift_ids' : [(5,)]})
data = { data = {
'info_session' : self.info_session, 'info_session' : self.info_session,
'info_session_date': self.info_session_date, 'info_session_date': self.info_session_date,
@ -88,7 +91,10 @@ class Subscribe(models.TransientModel):
'exempt_reason_id' : self.exempt_reason_id.id, 'exempt_reason_id' : self.exempt_reason_id.id,
'super' : self.super, 'super' : self.super,
'cooperator_id': self.cooperator_id.id, '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: if self.reset_counter:
data['sr'] = 0 data['sr'] = 0
@ -103,3 +109,5 @@ class Subscribe(models.TransientModel):
status_id.sudo().write(data) status_id.sudo().write(data)
else: else:
self.env['cooperative.status'].sudo().create(data) self.env['cooperative.status'].sudo().create(data)

1
beesdoo_shift/wizard/subscribe.xml

@ -15,6 +15,7 @@
<field name="working_mode" /> <field name="working_mode" />
<field name="exempt_reason_id" attrs="{'invisible':[('working_mode', '!=', 'exempt')]}"/> <field name="exempt_reason_id" attrs="{'invisible':[('working_mode', '!=', 'exempt')]}"/>
<field name="shift_id" domain="[('remaining_worker', '>', 0)]" attrs="{'invisible': [('working_mode', '!=', 'regular')]}"/> <field name="shift_id" domain="[('remaining_worker', '>', 0)]" attrs="{'invisible': [('working_mode', '!=', 'regular')]}"/>
<field name="irregular_start_date" attrs="{'invisible': [('working_mode', '!=', 'irregular')]}" />
<field name="super" /> <field name="super" />
<field name="reset_counter" /> <field name="reset_counter" />
<field name="reset_compensation_counter" /> <!-- TODO access right --> <field name="reset_compensation_counter" /> <!-- TODO access right -->

Loading…
Cancel
Save