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.
392 lines
15 KiB
392 lines
15 KiB
from odoo import models, fields, api, _
|
|
from odoo.exceptions import ValidationError, UserError
|
|
|
|
from datetime import timedelta, datetime
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
def add_days_delta(date_from, days_delta):
|
|
if not date_from:
|
|
return date_from
|
|
next_date = date_from + timedelta(days=days_delta)
|
|
return next_date
|
|
|
|
class ExemptReason(models.Model):
|
|
_name = 'cooperative.exempt.reason'
|
|
|
|
name = fields.Char(required=True)
|
|
|
|
class HistoryStatus(models.Model):
|
|
_name = 'cooperative.status.history'
|
|
|
|
_order= 'create_date desc'
|
|
|
|
status_id = fields.Many2one('cooperative.status')
|
|
cooperator_id = fields.Many2one('res.partner')
|
|
change = fields.Char()
|
|
type = fields.Selection([('status', 'Status Change'), ('counter', 'Counter Change')])
|
|
user_id = fields.Many2one('res.users', string="User")
|
|
|
|
class CooperativeStatus(models.Model):
|
|
_name = 'cooperative.status'
|
|
_rec_name = 'cooperator_id'
|
|
_order = 'cooperator_id'
|
|
_period = 28
|
|
|
|
def _get_status(self):
|
|
return [
|
|
('ok', 'Up to Date'),
|
|
('holiday', 'Holidays'),
|
|
('alert', 'Alerte'),
|
|
('extension', 'Extension'),
|
|
('suspended', 'Suspended'),
|
|
('exempted', 'Exempted'),
|
|
('unsubscribed', 'Unsubscribed'),
|
|
('resigning', 'Resigning')
|
|
]
|
|
|
|
today = fields.Date(help="Field that allow to compute field and store them even if they are based on the current date", default=fields.Date.today)
|
|
cooperator_id = fields.Many2one('res.partner')
|
|
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')
|
|
super = fields.Boolean("Super Cooperative")
|
|
sr = fields.Integer("Regular shifts counter", default=0)
|
|
sc = fields.Integer("Compensation shifts counter", default=0)
|
|
time_extension = fields.Integer("Extension Days NB", default=0, help="Addtional days to the automatic extension, 5 mean that you have a total of 15 extension days of default one is set to 10")
|
|
holiday_start_time = fields.Date("Holidays Start Day")
|
|
holiday_end_time = fields.Date("Holidays End Day")
|
|
alert_start_time = fields.Date("Alert Start Day")
|
|
extension_start_time = fields.Date("Extension Start Day")
|
|
working_mode = fields.Selection(
|
|
[
|
|
('regular', 'Regular worker'),
|
|
('irregular', 'Irregular worker'),
|
|
('exempt', 'Exempted'),
|
|
],
|
|
string="Working mode"
|
|
)
|
|
exempt_reason_id = fields.Many2one('cooperative.exempt.reason', 'Exempt Reason')
|
|
status = fields.Selection(selection=_get_status,
|
|
compute="_compute_status", string="Cooperative Status", store=True)
|
|
can_shop = fields.Boolean(compute='_compute_can_shop', store=True)
|
|
history_ids = fields.One2many('cooperative.status.history', 'status_id', readonly=True)
|
|
unsubscribed = fields.Boolean(default=False, help="Manually unsubscribed")
|
|
resigning = fields.Boolean(default=False, help="Want to leave the beescoop")
|
|
|
|
#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
|
|
future_alert_date = fields.Date(compute='_compute_future_alert_date')
|
|
next_countdown_date = fields.Date(compute='_compute_next_countdown_date')
|
|
|
|
temporary_exempt_reason_id = fields.Many2one('cooperative.exempt.reason', 'Exempt Reason')
|
|
temporary_exempt_start_date = fields.Date()
|
|
temporary_exempt_end_date = fields.Date()
|
|
|
|
@api.depends('status')
|
|
def _compute_can_shop(self):
|
|
for rec in self:
|
|
rec.can_shop = rec.status in self._can_shop_status()
|
|
|
|
@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', 'temporary_exempt_start_date',
|
|
'temporary_exempt_end_date', 'resigning', 'cooperator_id.subscribed_shift_ids')
|
|
def _compute_status(self):
|
|
update = int(self.env['ir.config_parameter'].sudo().get_param('always_update', False))
|
|
for rec in self:
|
|
if update or not rec.today:
|
|
rec.status = 'ok'
|
|
continue
|
|
if rec.resigning:
|
|
rec.status = 'resigning'
|
|
continue
|
|
|
|
if rec.working_mode == 'regular':
|
|
rec.status = rec._get_regular_status()
|
|
elif rec.working_mode == 'irregular':
|
|
rec.status = rec._get_irregular_status()
|
|
elif rec.working_mode == 'exempt':
|
|
rec.status = 'ok'
|
|
|
|
_sql_constraints = [
|
|
('cooperator_uniq', 'unique (cooperator_id)', _('You can only set one cooperator status per cooperator')),
|
|
]
|
|
|
|
@api.constrains("working_mode", "irregular_start_date")
|
|
def _constrains_irregular_start_date(self):
|
|
if self.working_mode == "irregular" and not self.irregular_start_date:
|
|
raise UserError(_("Irregular workers must have an irregular start date."))
|
|
|
|
@api.multi
|
|
def write(self, vals):
|
|
"""
|
|
Overwrite write to historize the change
|
|
"""
|
|
for field in ['sr', 'sc', 'time_extension', 'extension_start_time', 'alert_start_time', 'unsubscribed']:
|
|
if not field in vals:
|
|
continue
|
|
for rec in self:
|
|
data = {
|
|
'status_id': rec.id,
|
|
'cooperator_id': rec.cooperator_id.id,
|
|
'type': 'counter',
|
|
'user_id': self.env.context.get('real_uid', self.env.uid),
|
|
}
|
|
if vals.get(field, rec[field]) != rec[field]:
|
|
data['change'] = '%s: %s -> %s' % (field.upper(), rec[field], vals.get(field))
|
|
self.env['cooperative.status.history'].sudo().create(data)
|
|
return super(CooperativeStatus, self).write(vals)
|
|
|
|
@api.multi
|
|
def _write(self, vals):
|
|
"""
|
|
Overwrite write to historize the change of status
|
|
and make action on status change
|
|
"""
|
|
if 'status' in vals:
|
|
self._cr.execute('select id, status, sr, sc from "%s" where id in %%s' % self._table, (self._ids,))
|
|
result = self._cr.dictfetchall()
|
|
old_status_per_id = {r['id'] : r for r in result}
|
|
for rec in self:
|
|
if old_status_per_id[rec.id]['status'] != vals['status']:
|
|
data = {
|
|
'status_id': rec.id,
|
|
'cooperator_id': rec.cooperator_id.id,
|
|
'type': 'status',
|
|
'change': "STATUS: %s -> %s" % (old_status_per_id[rec.id]['status'], vals['status']),
|
|
'user_id': self.env.context.get('real_uid', self.env.uid),
|
|
}
|
|
self.env['cooperative.status.history'].sudo().create(data)
|
|
rec._state_change(vals['status'])
|
|
return super(CooperativeStatus, self)._write(vals)
|
|
|
|
def get_status_value(self):
|
|
"""
|
|
Workararound to get translated selection value instead of key in mail template.
|
|
"""
|
|
state_list = self.env["cooperative.status"]._fields['status']._description_selection(self.env)
|
|
return dict(state_list)[self.status]
|
|
|
|
@api.model
|
|
def _set_today(self):
|
|
"""
|
|
Method call by the cron to update store value base on the date
|
|
"""
|
|
self.search([]).write({'today': fields.Date.today()})
|
|
|
|
@api.model
|
|
def _cron_compute_counter_irregular(self, today=False):
|
|
"""
|
|
Journal ensure that a irregular worker will be only check
|
|
once per day
|
|
"""
|
|
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})
|
|
|
|
domain = self._get_irregular_worker_domain()
|
|
irregular = self.search(domain)
|
|
for status in irregular:
|
|
delta = (today - status.irregular_start_date).days
|
|
if delta and delta % self._period == 0 and status not in journal.line_ids:
|
|
status._change_irregular_counter()
|
|
journal.line_ids |= status
|
|
|
|
@api.multi
|
|
def clear_history(self):
|
|
self.ensure_one()
|
|
self.history_ids.unlink()
|
|
|
|
########################################################
|
|
# Method to override #
|
|
# To define the behavior of the status #
|
|
# #
|
|
# By default: everyone is always up to date #
|
|
########################################################
|
|
|
|
##############################
|
|
# Computed field section #
|
|
##############################
|
|
@api.depends('today')
|
|
def _compute_future_alert_date(self):
|
|
"""
|
|
Compute date until the worker is up to date
|
|
for irregular worker
|
|
"""
|
|
for rec in self:
|
|
rec.future_alert_date = False
|
|
|
|
@api.depends('today')
|
|
def _compute_next_countdown_date(self):
|
|
"""
|
|
Compute the following countdown date. This date is the date when
|
|
the worker will see his counter changed due to the cron. This
|
|
date is like the birthday date of the worker that occurred each
|
|
_period.
|
|
"""
|
|
for rec in self:
|
|
rec.next_countdown_date = False
|
|
|
|
def _can_shop_status(self):
|
|
"""
|
|
return the list of status that give access
|
|
to active cooperator privilege
|
|
"""
|
|
return ['ok', 'alert', 'extension', 'exempted']
|
|
|
|
#####################################
|
|
# Status Change implementation #
|
|
#####################################
|
|
|
|
def _get_regular_status(self):
|
|
"""
|
|
Return the value of the status
|
|
for the regular worker
|
|
"""
|
|
return 'ok'
|
|
|
|
def _get_irregular_status(self):
|
|
"""
|
|
Return the value of the status
|
|
for the irregular worker
|
|
"""
|
|
return 'ok'
|
|
|
|
def _state_change(self, new_state):
|
|
"""
|
|
Hook to watch change in the state
|
|
"""
|
|
pass
|
|
|
|
def _change_counter(self, data):
|
|
"""
|
|
Call when a shift state is changed
|
|
use data generated by _get_counter_date_state_change
|
|
"""
|
|
pass
|
|
|
|
|
|
###############################################
|
|
###### Irregular Cron implementation ##########
|
|
###############################################
|
|
|
|
def _get_irregular_worker_domain(self):
|
|
"""
|
|
return the domain the give the list
|
|
of valid irregular worker that should
|
|
get their counter changed by the cron
|
|
"""
|
|
return [(0, '=', 1)]
|
|
|
|
def _change_irregular_counter(self):
|
|
"""
|
|
Define how the counter will change
|
|
for the irregular worker
|
|
where today - start_date is a multiple of the period
|
|
by default 28 days
|
|
"""
|
|
pass
|
|
|
|
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):
|
|
"""
|
|
One2many relationship with CooperativeStatus should
|
|
be replaced by inheritance.
|
|
"""
|
|
_inherit = 'res.partner'
|
|
|
|
worker_store = fields.Boolean(default=False)
|
|
is_worker = fields.Boolean(related="worker_store", string="Worker", readonly=False)
|
|
cooperative_status_ids = fields.One2many('cooperative.status', 'cooperator_id', readonly=True)
|
|
super = fields.Boolean(related='cooperative_status_ids.super', string="Super Cooperative", readonly=True, store=True)
|
|
info_session = fields.Boolean(related='cooperative_status_ids.info_session', string='Information Session ?', readonly=True, store=True)
|
|
info_session_date = fields.Date(related='cooperative_status_ids.info_session_date', string='Information Session Date', readonly=True, store=True)
|
|
working_mode = fields.Selection(related='cooperative_status_ids.working_mode', readonly=True, store=True)
|
|
exempt_reason_id = fields.Many2one(related='cooperative_status_ids.exempt_reason_id', readonly=True, store=True)
|
|
state = fields.Selection(related='cooperative_status_ids.status', readonly=True, store=True)
|
|
extension_start_time = fields.Date(related='cooperative_status_ids.extension_start_time', string="Extension Start Day", readonly=True, store=True)
|
|
subscribed_shift_ids = fields.Many2many('beesdoo.shift.template')
|
|
|
|
@api.multi
|
|
def coop_subscribe(self):
|
|
return {
|
|
'name': _('Subscribe Cooperator'),
|
|
'type': 'ir.actions.act_window',
|
|
'view_type': 'form',
|
|
'view_mode': 'form',
|
|
'res_model': 'beesdoo.shift.subscribe',
|
|
'target': 'new',
|
|
}
|
|
|
|
@api.multi
|
|
def coop_unsubscribe(self):
|
|
res = self.coop_subscribe()
|
|
res['context'] = {'default_unsubscribed': True}
|
|
return res
|
|
|
|
@api.multi
|
|
def manual_extension(self):
|
|
return {
|
|
'name': _('Manual Extension'),
|
|
'type': 'ir.actions.act_window',
|
|
'view_type': 'form',
|
|
'view_mode': 'form',
|
|
'res_model': 'beesdoo.shift.extension',
|
|
'target': 'new',
|
|
}
|
|
|
|
@api.multi
|
|
def auto_extension(self):
|
|
res = self.manual_extension()
|
|
res['context'] = {'default_auto': True}
|
|
res['name'] = _('Trigger Grace Delay')
|
|
return res
|
|
|
|
@api.multi
|
|
def register_holiday(self):
|
|
return {
|
|
'name': _('Register Holiday'),
|
|
'type': 'ir.actions.act_window',
|
|
'view_type': 'form',
|
|
'view_mode': 'form',
|
|
'res_model': 'beesdoo.shift.holiday',
|
|
'target': 'new',
|
|
}
|
|
|
|
@api.multi
|
|
def temporary_exempt(self):
|
|
return {
|
|
'name': _('Temporary Exemption'),
|
|
'type': 'ir.actions.act_window',
|
|
'view_type': 'form',
|
|
'view_mode': 'form',
|
|
'res_model': 'beesdoo.shift.temporary_exemption',
|
|
'target': 'new',
|
|
}
|
|
|
|
#TODO access right + vue on res.partner
|