lims_administrative_task: add task scheduling
This commit is contained in:
parent
32368c132d
commit
e39f5eef02
|
@ -14,6 +14,8 @@ def register():
|
|||
task.AdministrativeTaskTemplate,
|
||||
task.AdministrativeTask,
|
||||
task.EditAdministrativeTaskStart,
|
||||
task.AdministrativeTaskProgram,
|
||||
task.GenerateAdministrativeTaskStart,
|
||||
department.Department,
|
||||
user.User,
|
||||
configuration.Configuration,
|
||||
|
@ -21,4 +23,5 @@ def register():
|
|||
module='lims_administrative_task', type_='model')
|
||||
Pool.register(
|
||||
task.EditAdministrativeTask,
|
||||
task.GenerateAdministrativeTask,
|
||||
module='lims_administrative_task', type_='wizard')
|
||||
|
|
|
@ -10,6 +10,10 @@ msgctxt "field:lims.administrative.task,closing_date:"
|
|||
msgid "Closing Date"
|
||||
msgstr "Fecha de cierre"
|
||||
|
||||
msgctxt "field:lims.administrative.task,color:"
|
||||
msgid "Color"
|
||||
msgstr "Color"
|
||||
|
||||
msgctxt "field:lims.administrative.task,comments:"
|
||||
msgid "Comments"
|
||||
msgstr "Observaciones"
|
||||
|
@ -50,6 +54,10 @@ msgctxt "field:lims.administrative.task,responsible:"
|
|||
msgid "Responsible User"
|
||||
msgstr "Usuario responsable"
|
||||
|
||||
msgctxt "field:lims.administrative.task,scheduled:"
|
||||
msgid "Scheduled"
|
||||
msgstr "Programada"
|
||||
|
||||
msgctxt "field:lims.administrative.task,state:"
|
||||
msgid "State"
|
||||
msgstr "Estado"
|
||||
|
@ -87,6 +95,42 @@ msgctxt "field:lims.administrative.task.edit.start,responsible:"
|
|||
msgid "Responsible User"
|
||||
msgstr "Usuario responsable"
|
||||
|
||||
msgctxt "field:lims.administrative.task.generate.start,end_date:"
|
||||
msgid "End Date"
|
||||
msgstr "Fecha de finalización"
|
||||
|
||||
msgctxt "field:lims.administrative.task.generate.start,start_date:"
|
||||
msgid "Start Date"
|
||||
msgstr "Fecha de inicio"
|
||||
|
||||
msgctxt "field:lims.administrative.task.generate.start,task_program:"
|
||||
msgid "Administrative Task Scheduling"
|
||||
msgstr "Programación de Tarea administrativa"
|
||||
|
||||
msgctxt "field:lims.administrative.task.generate.start,tasks:"
|
||||
msgid "Tasks"
|
||||
msgstr "Tareas"
|
||||
|
||||
msgctxt "field:lims.administrative.task.program,description:"
|
||||
msgid "Description"
|
||||
msgstr "Descripción"
|
||||
|
||||
msgctxt "field:lims.administrative.task.program,frequency:"
|
||||
msgid "Frequency"
|
||||
msgstr "Frecuencia"
|
||||
|
||||
msgctxt "field:lims.administrative.task.program,latest_date:"
|
||||
msgid "Latest scheduled date"
|
||||
msgstr "Última fecha programada"
|
||||
|
||||
msgctxt "field:lims.administrative.task.program,responsible:"
|
||||
msgid "Responsible User"
|
||||
msgstr "Usuario responsable"
|
||||
|
||||
msgctxt "field:lims.administrative.task.program,type:"
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
msgctxt "field:lims.administrative.task.template,description:"
|
||||
msgid "Description"
|
||||
msgstr "Descripción"
|
||||
|
@ -116,6 +160,10 @@ msgctxt "model:ir.action,name:act_task"
|
|||
msgid "All Administrative Tasks"
|
||||
msgstr "Todas las tareas administrativas"
|
||||
|
||||
msgctxt "model:ir.action,name:act_task_calendar_list"
|
||||
msgid "Administrative Tasks Calendar"
|
||||
msgstr "Calendario de Tareas administrativas"
|
||||
|
||||
msgctxt "model:ir.action,name:act_task_configuration"
|
||||
msgid "Configuration"
|
||||
msgstr "Configuración"
|
||||
|
@ -124,6 +172,10 @@ msgctxt "model:ir.action,name:act_task_mine"
|
|||
msgid "My Administrative Tasks"
|
||||
msgstr "Mis tareas administrativas"
|
||||
|
||||
msgctxt "model:ir.action,name:act_task_program_list"
|
||||
msgid "Administrative Tasks Scheduling"
|
||||
msgstr "Programación de Tareas administrativas"
|
||||
|
||||
msgctxt "model:ir.action,name:act_task_template"
|
||||
msgid "Administrative Tasks Configuration"
|
||||
msgstr "Configuración de Tareas administrativas"
|
||||
|
@ -132,6 +184,10 @@ msgctxt "model:ir.action,name:wiz_edit_task"
|
|||
msgid "Edit Administrative Task"
|
||||
msgstr "Editar Tarea administrativa"
|
||||
|
||||
msgctxt "model:ir.action,name:wizard_generate_task_calendar"
|
||||
msgid "Generate Administrative Tasks Calendar"
|
||||
msgstr "Generar Calendario de Tareas administrativas"
|
||||
|
||||
msgctxt "model:ir.action.act_window.domain,name:act_task_domain_all"
|
||||
msgid "All"
|
||||
msgstr "Todas"
|
||||
|
@ -250,6 +306,10 @@ msgctxt "model:ir.ui.menu,name:menu_task"
|
|||
msgid "All Administrative Tasks"
|
||||
msgstr "Todas las tareas administrativas"
|
||||
|
||||
msgctxt "model:ir.ui.menu,name:menu_task_calendar"
|
||||
msgid "Calendar"
|
||||
msgstr "Calendario"
|
||||
|
||||
msgctxt "model:ir.ui.menu,name:menu_task_configuration"
|
||||
msgid "Configuration"
|
||||
msgstr "Configuración"
|
||||
|
@ -258,6 +318,10 @@ msgctxt "model:ir.ui.menu,name:menu_task_mine"
|
|||
msgid "My Administrative Tasks"
|
||||
msgstr "Mis tareas administrativas"
|
||||
|
||||
msgctxt "model:ir.ui.menu,name:menu_task_program"
|
||||
msgid "Administrative Tasks Scheduling"
|
||||
msgstr "Programación de Tareas administrativas"
|
||||
|
||||
msgctxt "model:ir.ui.menu,name:menu_task_template"
|
||||
msgid "Automatic generation of administrative tasks"
|
||||
msgstr "Generación automática de Tareas administrativas"
|
||||
|
@ -278,6 +342,14 @@ msgctxt "model:lims.administrative.task.edit.start,name:"
|
|||
msgid "Edit Administrative Task"
|
||||
msgstr "Editar Tarea administrativa"
|
||||
|
||||
msgctxt "model:lims.administrative.task.generate.start,name:"
|
||||
msgid "Generate Administrative Tasks Calendar"
|
||||
msgstr "Generar Calendario de Tareas administrativas"
|
||||
|
||||
msgctxt "model:lims.administrative.task.program,name:"
|
||||
msgid "Administrative Task Scheduling"
|
||||
msgstr "Programación de Tarea administrativa"
|
||||
|
||||
msgctxt "model:lims.administrative.task.template,name:"
|
||||
msgid "Administrative Task Configuration"
|
||||
msgstr "Configuración de Tarea administrativa"
|
||||
|
@ -358,6 +430,22 @@ msgctxt "selection:lims.administrative.task.edit.start,priority:"
|
|||
msgid "Very Low"
|
||||
msgstr "Muy baja"
|
||||
|
||||
msgctxt "selection:lims.administrative.task.program,frequency:"
|
||||
msgid "Daily"
|
||||
msgstr "Diaria"
|
||||
|
||||
msgctxt "selection:lims.administrative.task.program,frequency:"
|
||||
msgid "Monthly"
|
||||
msgstr "Mensual"
|
||||
|
||||
msgctxt "selection:lims.administrative.task.program,frequency:"
|
||||
msgid "Weekly"
|
||||
msgstr "Semanal"
|
||||
|
||||
msgctxt "selection:lims.administrative.task.program,frequency:"
|
||||
msgid "Yearly"
|
||||
msgstr "Anual"
|
||||
|
||||
msgctxt "view:lims.administrative.task:"
|
||||
msgid "Comments"
|
||||
msgstr "Observaciones"
|
||||
|
@ -393,3 +481,11 @@ msgstr "Confirmar"
|
|||
msgctxt "wizard_button:lims.administrative.task.edit,start,end:"
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
msgctxt "wizard_button:lims.administrative.task.generate,start,end:"
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
msgctxt "wizard_button:lims.administrative.task.generate,start,generate:"
|
||||
msgid "Generate"
|
||||
msgstr "Generar"
|
||||
|
|
|
@ -8,9 +8,10 @@ from email.mime.multipart import MIMEMultipart
|
|||
from email.header import Header
|
||||
|
||||
from trytond.model import Workflow, ModelSQL, ModelView, fields
|
||||
from trytond.pyson import Eval
|
||||
from trytond.pyson import PYSONEncoder, Eval
|
||||
from trytond.pool import Pool
|
||||
from trytond.wizard import Wizard, StateTransition, StateView, Button
|
||||
from trytond.wizard import Wizard, StateTransition, StateView, StateAction, \
|
||||
Button
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.exceptions import UserError
|
||||
from trytond.i18n import gettext
|
||||
|
@ -113,6 +114,8 @@ class AdministrativeTask(Workflow, ModelSQL, ModelView):
|
|||
], 'State', select=True, readonly=True, required=True)
|
||||
icon = fields.Function(fields.Char('Icon'), 'get_icon')
|
||||
comments = fields.Text('Comments')
|
||||
scheduled = fields.Boolean('Scheduled', readonly=True)
|
||||
color = fields.Function(fields.Char('Color'), 'get_color')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
|
@ -159,6 +162,10 @@ class AdministrativeTask(Workflow, ModelSQL, ModelView):
|
|||
def default_priority():
|
||||
return '3'
|
||||
|
||||
@staticmethod
|
||||
def default_scheduled():
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
pool = Pool()
|
||||
|
@ -190,16 +197,22 @@ class AdministrativeTask(Workflow, ModelSQL, ModelView):
|
|||
super().delete(tasks)
|
||||
|
||||
def get_date(self, name):
|
||||
if self.scheduled:
|
||||
return self.expiration_date
|
||||
return self.create_date.date()
|
||||
|
||||
@classmethod
|
||||
def search_date(cls, name, clause):
|
||||
cursor = Transaction().connection.cursor()
|
||||
operator_ = clause[1:2][0]
|
||||
value = clause[2:3][0]
|
||||
cursor.execute('SELECT id '
|
||||
'FROM "' + cls._table + '" '
|
||||
'WHERE create_date::date ' + operator_ + ' %s',
|
||||
clause[2:3])
|
||||
'WHERE (scheduled IS FALSE AND create_date::date '
|
||||
+ operator_ + ' %s) '
|
||||
'OR (scheduled IS TRUE AND expiration_date::date '
|
||||
+ operator_ + ' %s)',
|
||||
(value, value))
|
||||
return [('id', 'in', [x[0] for x in cursor.fetchall()])]
|
||||
|
||||
@classmethod
|
||||
|
@ -232,6 +245,15 @@ class AdministrativeTask(Workflow, ModelSQL, ModelView):
|
|||
result[t.id] = 'lims-red'
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_color(cls, tasks, name):
|
||||
result = {}
|
||||
for t in tasks:
|
||||
result[t.id] = 'lightgray'
|
||||
if t.state in ('pending', 'ongoing', 'standby'):
|
||||
result[t.id] = 'lightblue'
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def check_transition(cls, records, state):
|
||||
filtered = []
|
||||
|
@ -321,6 +343,8 @@ class AdministrativeTask(Workflow, ModelSQL, ModelView):
|
|||
logger.error("Missing address for '%s' to send email",
|
||||
task.responsible.rec_name)
|
||||
continue
|
||||
if task.scheduled:
|
||||
continue
|
||||
|
||||
subject, body = task._get_subject_body()
|
||||
msg = cls.create_msg(from_addr, to_addr, subject, body)
|
||||
|
@ -455,3 +479,136 @@ class EditAdministrativeTask(Wizard):
|
|||
AdministrativeTask.send_email_responsible(tasks)
|
||||
|
||||
return 'end'
|
||||
|
||||
|
||||
class AdministrativeTaskProgram(ModelSQL, ModelView):
|
||||
'Administrative Task Scheduling'
|
||||
__name__ = 'lims.administrative.task.program'
|
||||
_rec_name = 'type'
|
||||
|
||||
type = fields.Selection('get_types', 'Type', required=True)
|
||||
description = fields.Char('Description', required=True)
|
||||
responsible = fields.Many2One('res.user', 'Responsible User',
|
||||
required=True)
|
||||
frequency = fields.Selection([
|
||||
('daily', 'Daily'),
|
||||
('weekly', 'Weekly'),
|
||||
('monthly', 'Monthly'),
|
||||
('yearly', 'Yearly'),
|
||||
], 'Frequency', required=True, sort=False)
|
||||
latest_date = fields.Function(fields.Date('Latest scheduled date'),
|
||||
'get_latest_date')
|
||||
|
||||
@classmethod
|
||||
def get_types(cls):
|
||||
AdministrativeTaskTemplate = Pool().get(
|
||||
'lims.administrative.task.template')
|
||||
return AdministrativeTaskTemplate.get_types()
|
||||
|
||||
@classmethod
|
||||
def get_latest_date(cls, programs, name):
|
||||
AdministrativeTask = Pool().get('lims.administrative.task')
|
||||
result = {}
|
||||
for p in programs:
|
||||
latest_task = AdministrativeTask.search([
|
||||
('type', '=', p.type),
|
||||
('responsible', '=', p.responsible.id),
|
||||
('state', '=', 'pending'),
|
||||
], order=[('date', 'DESC')], limit=1)
|
||||
result[p.id] = (latest_task and
|
||||
latest_task[0].date or None)
|
||||
return result
|
||||
|
||||
|
||||
class GenerateAdministrativeTaskStart(ModelView):
|
||||
'Generate Administrative Tasks Calendar'
|
||||
__name__ = 'lims.administrative.task.generate.start'
|
||||
|
||||
start_date = fields.Date('Start Date', required=True)
|
||||
end_date = fields.Date('End Date', required=True)
|
||||
task_program = fields.Many2Many(
|
||||
'lims.administrative.task.program', None, None,
|
||||
'Administrative Task Scheduling', required=True)
|
||||
tasks = fields.One2Many('lims.administrative.task',
|
||||
None, 'Tasks')
|
||||
|
||||
|
||||
class GenerateAdministrativeTask(Wizard):
|
||||
'Generate Administrative Tasks Calendar'
|
||||
__name__ = 'lims.administrative.task.generate'
|
||||
|
||||
start = StateView('lims.administrative.task.generate.start',
|
||||
'lims_administrative_task.generate_task_calendar_start_view_form', [
|
||||
Button('Cancel', 'end', 'tryton-cancel'),
|
||||
Button('Generate', 'generate', 'tryton-ok', default=True),
|
||||
])
|
||||
generate = StateTransition()
|
||||
open = StateAction('lims_administrative_task.act_task')
|
||||
|
||||
def default_start(self, fields):
|
||||
Date = Pool().get('ir.date')
|
||||
|
||||
today = Date.today()
|
||||
programs = Transaction().context['active_ids']
|
||||
defaults = {
|
||||
'start_date': today,
|
||||
'end_date': today,
|
||||
'task_program': programs,
|
||||
}
|
||||
return defaults
|
||||
|
||||
def transition_generate(self):
|
||||
AdministrativeTask = Pool().get('lims.administrative.task')
|
||||
|
||||
new_tasks = []
|
||||
for program in self.start.task_program:
|
||||
new_tasks.extend(self._get_new_tasks(program))
|
||||
|
||||
tasks = AdministrativeTask.create(new_tasks)
|
||||
if tasks:
|
||||
AdministrativeTask.pending(tasks)
|
||||
self.start.tasks = tasks
|
||||
return 'open'
|
||||
|
||||
return 'end'
|
||||
|
||||
def _get_new_tasks(self, program):
|
||||
new_tasks = []
|
||||
for date in self._get_dates(self.start.start_date,
|
||||
program.frequency, self.start.end_date):
|
||||
task = {
|
||||
'type': program.type,
|
||||
'description': program.description,
|
||||
'responsible': program.responsible.id,
|
||||
'expiration_date': date,
|
||||
'priority': '3',
|
||||
'state': 'draft',
|
||||
'scheduled': True,
|
||||
}
|
||||
new_tasks.append(task)
|
||||
return new_tasks
|
||||
|
||||
def _get_dates(self, start_date, frequency, end_date):
|
||||
dates = []
|
||||
if frequency == 'daily':
|
||||
delta = relativedelta(days=1)
|
||||
elif frequency == 'weekly':
|
||||
delta = relativedelta(days=7)
|
||||
elif frequency == 'monthly':
|
||||
delta = relativedelta(months=1)
|
||||
elif frequency == 'yearly':
|
||||
delta = relativedelta(years=1)
|
||||
date = start_date
|
||||
while date <= end_date:
|
||||
dates.append(date)
|
||||
date += delta
|
||||
return dates
|
||||
|
||||
def do_open(self, action):
|
||||
action['pyson_domain'] = PYSONEncoder().encode([
|
||||
('id', 'in', [m.id for m in self.start.tasks]),
|
||||
])
|
||||
return action, {}
|
||||
|
||||
def transition_open(self):
|
||||
return 'end'
|
||||
|
|
|
@ -304,5 +304,97 @@
|
|||
<field name="action" ref="wiz_edit_task"/>
|
||||
</record>
|
||||
|
||||
<!-- Administrative Tasks Scheduling -->
|
||||
|
||||
<record model="ir.ui.view" id="task_program_view_form">
|
||||
<field name="model">lims.administrative.task.program</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">task_program_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="task_program_view_list">
|
||||
<field name="model">lims.administrative.task.program</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">task_program_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_task_program_list">
|
||||
<field name="name">Administrative Tasks Scheduling</field>
|
||||
<field name="res_model">lims.administrative.task.program</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_task_program_view_list">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="task_program_view_list"/>
|
||||
<field name="act_window" ref="act_task_program_list"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_task_program_view_form">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="task_program_view_form"/>
|
||||
<field name="act_window" ref="act_task_program_list"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Administrative Tasks Scheduling"
|
||||
action="act_task_program_list"
|
||||
id="menu_task_program"
|
||||
parent="menu_config" sequence="30"/>
|
||||
|
||||
<!-- Wizard Generate Administrative Tasks Calendar -->
|
||||
|
||||
<record model="ir.ui.view"
|
||||
id="generate_task_calendar_start_view_form">
|
||||
<field name="model">lims.administrative.task.generate.start</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">generate_task_calendar_start_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.wizard" id="wizard_generate_task_calendar">
|
||||
<field name="name">Generate Administrative Tasks Calendar</field>
|
||||
<field name="wiz_name">lims.administrative.task.generate</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.keyword"
|
||||
id="wizard_generate_task_calendar_keyword">
|
||||
<field name="keyword">form_action</field>
|
||||
<field name="model">lims.administrative.task.program,-1</field>
|
||||
<field name="action" ref="wizard_generate_task_calendar"/>
|
||||
</record>
|
||||
|
||||
<!-- Administrative Tasks Calendar -->
|
||||
|
||||
<record model="ir.ui.view" id="task_view_calendar">
|
||||
<field name="model">lims.administrative.task</field>
|
||||
<field name="type">calendar</field>
|
||||
<field name="name">task_calendar</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_task_calendar_list">
|
||||
<field name="name">Administrative Tasks Calendar</field>
|
||||
<field name="res_model">lims.administrative.task</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_task_calendar_view_calendar">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="task_view_calendar"/>
|
||||
<field name="act_window" ref="act_task_calendar_list"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_task_calendar_view_list">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="task_view_list"/>
|
||||
<field name="act_window" ref="act_task_calendar_list"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_task_calendar_view_form">
|
||||
<field name="sequence" eval="30"/>
|
||||
<field name="view" ref="task_view_form"/>
|
||||
<field name="act_window" ref="act_task_calendar_list"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Calendar"
|
||||
action="act_task_calendar_list"
|
||||
id="menu_task_calendar"
|
||||
parent="menu_administrative_task" sequence="50"/>
|
||||
|
||||
</data>
|
||||
</tryton>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<form>
|
||||
<label name="start_date"/>
|
||||
<field name="start_date"/>
|
||||
<label name="end_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="task_program" colspan="4"/>
|
||||
</form>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<calendar dtstart="date" dtend="date" mode="month" background_color="color">
|
||||
<field name="description"/>
|
||||
<field name="responsible"/>
|
||||
</calendar>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0"?>
|
||||
<form>
|
||||
<label name="type"/>
|
||||
<field name="type"/>
|
||||
<label name="description"/>
|
||||
<field name="description"/>
|
||||
<label name="responsible"/>
|
||||
<field name="responsible"/>
|
||||
<label name="frequency"/>
|
||||
<field name="frequency"/>
|
||||
<label name="latest_date"/>
|
||||
<field name="latest_date"/>
|
||||
</form>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<tree>
|
||||
<field name="type"/>
|
||||
<field name="description"/>
|
||||
<field name="responsible"/>
|
||||
<field name="frequency"/>
|
||||
<field name="latest_date"/>
|
||||
</tree>
|
Loading…
Reference in New Issue