2017-10-08 02:23:22 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# This file is part of lims module for Tryton.
|
|
|
|
# The COPYRIGHT file at the top level of this repository contains
|
|
|
|
# the full copyright notices and license terms.
|
2020-05-25 21:58:43 +02:00
|
|
|
from datetime import datetime
|
2020-06-19 00:37:14 +02:00
|
|
|
from dateutil import rrule
|
2020-06-02 02:32:56 +02:00
|
|
|
from sql import Null
|
2017-10-08 02:23:22 +02:00
|
|
|
|
|
|
|
from trytond.model import ModelSingleton, ModelView, ModelSQL, fields
|
2021-09-23 00:59:40 +02:00
|
|
|
from trytond.pyson import Eval, Id
|
2017-10-08 02:23:22 +02:00
|
|
|
from trytond.transaction import Transaction
|
|
|
|
from trytond.pool import Pool, PoolMeta
|
|
|
|
from trytond.modules.company.model import (
|
|
|
|
CompanyMultiValueMixin, CompanyValueMixin)
|
2019-07-23 23:27:33 +02:00
|
|
|
from trytond.exceptions import UserError
|
|
|
|
from trytond.i18n import gettext
|
2017-10-08 02:23:22 +02:00
|
|
|
|
|
|
|
sequence_names = [
|
|
|
|
'entry_sequence', 'sample_sequence', 'service_sequence',
|
|
|
|
'results_report_sequence']
|
|
|
|
|
|
|
|
|
2020-05-25 21:58:43 +02:00
|
|
|
def get_print_date():
|
|
|
|
Company = Pool().get('company.company')
|
|
|
|
|
|
|
|
date = datetime.now()
|
|
|
|
company_id = Transaction().context.get('company')
|
|
|
|
if company_id:
|
|
|
|
date = Company(company_id).convert_timezone_datetime(date)
|
|
|
|
return date
|
|
|
|
|
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
class NotebookView(ModelSQL, ModelView):
|
2017-10-08 02:23:22 +02:00
|
|
|
'Laboratory Notebook View'
|
|
|
|
__name__ = 'lims.notebook.view'
|
|
|
|
|
|
|
|
name = fields.Char('Name', required=True)
|
|
|
|
columns = fields.One2Many('lims.notebook.view.column', 'view', 'Columns',
|
|
|
|
required=True)
|
|
|
|
|
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
class NotebookViewColumn(ModelSQL, ModelView):
|
2017-10-08 02:23:22 +02:00
|
|
|
'Laboratory Notebook View Column'
|
|
|
|
__name__ = 'lims.notebook.view.column'
|
|
|
|
|
|
|
|
view = fields.Many2One('lims.notebook.view', 'View', required=True,
|
|
|
|
ondelete='CASCADE', select=True)
|
|
|
|
field = fields.Many2One('ir.model.field', 'Field', required=True,
|
|
|
|
domain=[('model.model', '=', 'lims.notebook.line')])
|
|
|
|
sequence = fields.Integer('Sequence', required=True, select=True)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def __setup__(cls):
|
2020-08-06 19:52:36 +02:00
|
|
|
super().__setup__()
|
2017-10-08 02:23:22 +02:00
|
|
|
cls._order.insert(0, ('sequence', 'ASC'))
|
|
|
|
|
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
class Printer(ModelSQL, ModelView):
|
2017-10-08 02:23:22 +02:00
|
|
|
'Printer'
|
|
|
|
__name__ = 'lims.printer'
|
|
|
|
|
|
|
|
name = fields.Char('Name', required=True)
|
|
|
|
|
|
|
|
|
2019-03-04 15:41:58 +01:00
|
|
|
class User(metaclass=PoolMeta):
|
2017-10-08 02:23:22 +02:00
|
|
|
__name__ = 'res.user'
|
|
|
|
|
|
|
|
notebook_view = fields.Many2One('lims.notebook.view', 'Notebook view')
|
|
|
|
laboratories = fields.Many2Many('lims.user-laboratory',
|
|
|
|
'user', 'laboratory', 'Laboratories')
|
|
|
|
laboratory = fields.Many2One('lims.laboratory', 'Main Laboratory',
|
|
|
|
domain=[('id', 'in', Eval('laboratories'))], depends=['laboratories'])
|
|
|
|
printer = fields.Many2One('lims.printer', 'Printer')
|
2018-05-05 05:36:46 +02:00
|
|
|
departments = fields.One2Many('user.department', 'user', 'Departments')
|
2017-10-08 02:23:22 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def __setup__(cls):
|
2020-08-06 19:52:36 +02:00
|
|
|
super().__setup__()
|
2017-10-08 02:23:22 +02:00
|
|
|
cls._context_fields.insert(0, 'laboratory')
|
|
|
|
cls._context_fields.insert(0, 'laboratories')
|
|
|
|
|
|
|
|
@classmethod
|
2020-06-02 02:32:56 +02:00
|
|
|
def __register__(cls, module_name):
|
|
|
|
cursor = Transaction().connection.cursor()
|
2017-10-08 02:23:22 +02:00
|
|
|
pool = Pool()
|
2020-06-02 02:32:56 +02:00
|
|
|
Role = pool.get('res.role')
|
|
|
|
RoleGroup = pool.get('res.role-res.group')
|
|
|
|
UserRole = pool.get('res.user.role')
|
|
|
|
|
2020-08-06 19:52:36 +02:00
|
|
|
super().__register__(module_name)
|
2020-06-02 02:32:56 +02:00
|
|
|
|
|
|
|
user_sql_table = cls.__table__()
|
|
|
|
user_table = cls.__table_handler__(module_name)
|
|
|
|
if user_table.column_exist('role'):
|
|
|
|
role = Role.__table__()
|
|
|
|
role_group = RoleGroup.__table__()
|
|
|
|
user_role = UserRole.__table__()
|
|
|
|
|
|
|
|
cursor.execute('SELECT id, name '
|
|
|
|
'FROM lims_user_role')
|
|
|
|
for role_id, role_name in cursor.fetchall():
|
|
|
|
cursor.execute(*role.insert(
|
|
|
|
[role.id, role.name],
|
|
|
|
[[role_id, role_name]]))
|
|
|
|
|
|
|
|
cursor.execute('SELECT "group" '
|
|
|
|
'FROM "lims_user_role-res_group" '
|
|
|
|
'WHERE role = %s', (role_id, ))
|
|
|
|
for (group_id, ) in cursor.fetchall():
|
|
|
|
cursor.execute(*role_group.insert(
|
|
|
|
[role_group.role, role_group.group],
|
|
|
|
[[role_id, group_id]]))
|
|
|
|
|
|
|
|
cursor.execute(*user_sql_table.select(
|
|
|
|
user_sql_table.id, user_sql_table.role,
|
|
|
|
where=user_sql_table.role != Null))
|
|
|
|
for user_id, role_id in cursor.fetchall():
|
|
|
|
cursor.execute(*user_role.insert(
|
|
|
|
[user_role.user, user_role.role],
|
|
|
|
[[user_id, role_id]]))
|
|
|
|
|
|
|
|
user_table.drop_column('role')
|
2017-10-08 02:23:22 +02:00
|
|
|
|
|
|
|
def get_status_bar(self, name):
|
|
|
|
status = self.name
|
|
|
|
if self.company:
|
|
|
|
status = '%s - %s' % (self.company.rec_name, status)
|
|
|
|
if self.laboratory:
|
|
|
|
status += ' [%s]' % self.laboratory.rec_name
|
|
|
|
return status
|
|
|
|
|
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
class UserLaboratory(ModelSQL):
|
2017-10-08 02:23:22 +02:00
|
|
|
'User - Laboratory'
|
|
|
|
__name__ = 'lims.user-laboratory'
|
|
|
|
|
|
|
|
user = fields.Many2One('res.user', 'User',
|
|
|
|
ondelete='CASCADE', select=True, required=True)
|
|
|
|
laboratory = fields.Many2One('lims.laboratory', 'Laboratory',
|
|
|
|
ondelete='CASCADE', select=True, required=True)
|
|
|
|
|
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
class Configuration(ModelSingleton, ModelSQL, ModelView,
|
|
|
|
CompanyMultiValueMixin):
|
2017-10-08 02:23:22 +02:00
|
|
|
'Configuration'
|
|
|
|
__name__ = 'lims.configuration'
|
|
|
|
|
|
|
|
fraction_product = fields.Many2One('product.product', 'Fraction product',
|
|
|
|
states={'required': True})
|
|
|
|
mail_ack_subject = fields.Char('Email subject of Acknowledgment of Samples'
|
|
|
|
' Receipt',
|
|
|
|
help="In the text will be added suffix with the entry report number")
|
|
|
|
mail_ack_body = fields.Text('Email body of Acknowledgment of Samples'
|
|
|
|
' Receipt')
|
2022-03-30 17:20:13 +02:00
|
|
|
mail_ack_hide_recipients = fields.Boolean('Hide recipients')
|
2017-10-08 02:23:22 +02:00
|
|
|
microbiology_laboratories = fields.Many2Many(
|
|
|
|
'lims.configuration-laboratory', 'configuration',
|
|
|
|
'laboratory', 'Microbiology Laboratories')
|
|
|
|
default_notebook_view = fields.Many2One('lims.notebook.view',
|
|
|
|
'Default Notebook view', required=True)
|
|
|
|
brix_digits = fields.Integer('Brix digits')
|
|
|
|
density_digits = fields.Integer('Density digits')
|
|
|
|
soluble_solids_digits = fields.Integer('Soluble solids digits')
|
|
|
|
rm_start_uom = fields.Many2One('product.uom', 'RM Start UoM',
|
|
|
|
domain=[('category.lims_only_available', '=', True)])
|
|
|
|
email_qa = fields.Char('QA Email')
|
|
|
|
analysis_product_category = fields.Many2One('product.category',
|
|
|
|
'Analysis Product Category', states={'required': True})
|
|
|
|
entry_confirm_background = fields.Boolean(
|
|
|
|
'Confirm Entries in Background')
|
2018-05-05 05:36:46 +02:00
|
|
|
planification_sequence = fields.MultiValue(fields.Many2One(
|
|
|
|
'ir.sequence', 'Planification Sequence', required=True,
|
|
|
|
domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_planification')),
|
2018-05-05 05:36:46 +02:00
|
|
|
('company', 'in',
|
|
|
|
[Eval('context', {}).get('company', -1), None]),
|
|
|
|
]))
|
2020-08-07 07:43:40 +02:00
|
|
|
referral_sequence = fields.MultiValue(fields.Many2One(
|
|
|
|
'ir.sequence', 'Referral Sequence', required=True,
|
|
|
|
domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_referral')),
|
2020-08-07 07:43:40 +02:00
|
|
|
('company', 'in',
|
|
|
|
[Eval('context', {}).get('company', -1), None]),
|
|
|
|
]))
|
2018-05-05 05:36:46 +02:00
|
|
|
mcl_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'MCL fraction type')
|
|
|
|
con_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'Control fraction type')
|
|
|
|
bmz_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'BMZ fraction type')
|
|
|
|
rm_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'RM fraction type')
|
|
|
|
bre_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'BRE fraction type')
|
|
|
|
mrt_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'MRT fraction type')
|
|
|
|
coi_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'COI fraction type')
|
|
|
|
mrc_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'MRC fraction type')
|
|
|
|
sla_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'SLA fraction type')
|
|
|
|
itc_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'ITC fraction type')
|
|
|
|
itl_fraction_type = fields.Many2One('lims.fraction.type',
|
|
|
|
'ITL fraction type')
|
|
|
|
reagents = fields.Many2Many('lims.configuration-product.category',
|
|
|
|
'configuration', 'category', 'Reagents')
|
|
|
|
invoice_party_relation_type = fields.Many2One('party.relation.type',
|
|
|
|
'Invoice Party Relation Type')
|
2020-05-21 17:13:43 +02:00
|
|
|
samples_in_progress = fields.Selection([
|
|
|
|
('result', 'With results'),
|
|
|
|
('accepted', 'With accepted results'),
|
|
|
|
], 'Samples in progress',
|
|
|
|
help='Samples allowed for preliminary reports')
|
2020-06-09 16:58:07 +02:00
|
|
|
zone_required = fields.Boolean('Zone required')
|
2020-10-26 23:29:55 +01:00
|
|
|
entry_default_contacts = fields.Selection([
|
|
|
|
('party', 'Party'),
|
|
|
|
('invoice_party', 'Invoice party'),
|
|
|
|
], 'Default Contacts in Entries',
|
|
|
|
help='From which Party takes the contacts for the Entry')
|
2021-02-03 22:10:09 +01:00
|
|
|
notebook_lines_acceptance = fields.Selection([
|
|
|
|
('none', 'Do not accept analyzes that have repetition'),
|
|
|
|
('last', 'Accept the last repetition of the analyzes'),
|
|
|
|
], 'Acceptance of notebook lines')
|
2021-02-04 21:51:34 +01:00
|
|
|
notebook_lines_acceptance_method = fields.Boolean(
|
|
|
|
'Allow to accept the same analysis with different methods')
|
2021-09-09 17:36:00 +02:00
|
|
|
results_report_language = fields.Many2One('ir.lang',
|
|
|
|
'Results Report Language', domain=[('translatable', '=', True)])
|
2017-10-08 02:23:22 +02:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_brix_digits():
|
|
|
|
return 2
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_density_digits():
|
|
|
|
return 2
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_soluble_solids_digits():
|
|
|
|
return 2
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_entry_confirm_background():
|
|
|
|
return False
|
|
|
|
|
2022-03-30 17:20:13 +02:00
|
|
|
@staticmethod
|
|
|
|
def default_mail_ack_hide_recipients():
|
|
|
|
return True
|
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
@classmethod
|
|
|
|
def multivalue_model(cls, field):
|
|
|
|
pool = Pool()
|
2020-08-07 07:43:40 +02:00
|
|
|
if field in ['planification_sequence', 'referral_sequence']:
|
2018-05-05 05:36:46 +02:00
|
|
|
return pool.get('lims.configuration.sequence')
|
2020-08-06 19:52:36 +02:00
|
|
|
return super().multivalue_model(field)
|
2018-05-05 05:36:46 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_planification_sequence(cls, **pattern):
|
|
|
|
return cls.multivalue_model(
|
|
|
|
'planification_sequence').default_planification_sequence()
|
|
|
|
|
2020-08-07 07:43:40 +02:00
|
|
|
@classmethod
|
|
|
|
def default_referral_sequence(cls, **pattern):
|
|
|
|
return cls.multivalue_model(
|
|
|
|
'referral_sequence').default_referral_sequence()
|
|
|
|
|
2020-05-21 17:13:43 +02:00
|
|
|
@staticmethod
|
|
|
|
def default_samples_in_progress():
|
|
|
|
return 'result'
|
|
|
|
|
2020-06-09 16:58:07 +02:00
|
|
|
@staticmethod
|
|
|
|
def default_zone_required():
|
|
|
|
return True
|
|
|
|
|
2020-10-26 23:29:55 +01:00
|
|
|
@staticmethod
|
|
|
|
def default_entry_default_contacts():
|
|
|
|
return 'party'
|
|
|
|
|
2021-02-03 22:10:09 +01:00
|
|
|
@staticmethod
|
|
|
|
def default_notebook_lines_acceptance():
|
|
|
|
return 'none'
|
|
|
|
|
2021-02-04 21:51:34 +01:00
|
|
|
@staticmethod
|
|
|
|
def default_notebook_lines_acceptance_method():
|
|
|
|
return False
|
|
|
|
|
2021-09-09 17:36:00 +02:00
|
|
|
@staticmethod
|
|
|
|
def default_results_report_language():
|
|
|
|
Lang = Pool().get('ir.lang')
|
|
|
|
langs = Lang.search([
|
|
|
|
('translatable', '=', True),
|
|
|
|
('code', '=', 'es'),
|
|
|
|
])
|
|
|
|
return langs and langs[0].id or None
|
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
def get_reagents(self):
|
|
|
|
res = []
|
|
|
|
if self.reagents:
|
|
|
|
for r in self.reagents:
|
|
|
|
res.append(r.id)
|
|
|
|
res.extend(self.get_reagent_childs(r.id))
|
|
|
|
return res
|
|
|
|
|
|
|
|
def get_reagent_childs(self, reagent_id):
|
|
|
|
Category = Pool().get('product.category')
|
|
|
|
|
|
|
|
res = []
|
|
|
|
categories = Category.search([
|
|
|
|
('parent', '=', reagent_id),
|
|
|
|
])
|
|
|
|
if categories:
|
|
|
|
for c in categories:
|
|
|
|
res.append(c.id)
|
|
|
|
res.extend(self.get_reagent_childs(c.id))
|
|
|
|
return res
|
|
|
|
|
2017-10-08 02:23:22 +02:00
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
class ConfigurationLaboratory(ModelSQL):
|
2017-10-08 02:23:22 +02:00
|
|
|
'Configuration - Laboratory'
|
|
|
|
__name__ = 'lims.configuration-laboratory'
|
|
|
|
|
|
|
|
configuration = fields.Many2One('lims.configuration', 'Configuration',
|
|
|
|
ondelete='CASCADE', select=True, required=True)
|
|
|
|
laboratory = fields.Many2One('lims.laboratory', 'Laboratory',
|
|
|
|
ondelete='CASCADE', select=True, required=True)
|
|
|
|
|
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
class ConfigurationSequence(ModelSQL, CompanyValueMixin):
|
|
|
|
'Configuration Sequence'
|
|
|
|
__name__ = 'lims.configuration.sequence'
|
|
|
|
|
|
|
|
planification_sequence = fields.Many2One('ir.sequence',
|
|
|
|
'Planification Sequence', depends=['company'], domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_planification')),
|
2018-05-05 05:36:46 +02:00
|
|
|
('company', 'in', [Eval('company', -1), None]),
|
|
|
|
])
|
2020-08-07 07:43:40 +02:00
|
|
|
referral_sequence = fields.Many2One('ir.sequence',
|
|
|
|
'Referral Sequence', depends=['company'], domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_referral')),
|
2020-08-07 07:43:40 +02:00
|
|
|
('company', 'in', [Eval('company', -1), None]),
|
|
|
|
])
|
2018-05-05 05:36:46 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_planification_sequence(cls):
|
|
|
|
pool = Pool()
|
|
|
|
ModelData = pool.get('ir.model.data')
|
|
|
|
try:
|
|
|
|
return ModelData.get_id('lims.planification', 'seq_planification')
|
|
|
|
except KeyError:
|
|
|
|
return None
|
|
|
|
|
2020-08-07 07:43:40 +02:00
|
|
|
@classmethod
|
|
|
|
def default_referral_sequence(cls):
|
|
|
|
pool = Pool()
|
|
|
|
ModelData = pool.get('ir.model.data')
|
|
|
|
try:
|
|
|
|
return ModelData.get_id('lims.referral', 'seq_referral')
|
|
|
|
except KeyError:
|
|
|
|
return None
|
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
|
|
|
|
class ConfigurationProductCategory(ModelSQL):
|
|
|
|
'Configuration - Product Category'
|
|
|
|
__name__ = 'lims.configuration-product.category'
|
|
|
|
|
|
|
|
configuration = fields.Many2One('lims.configuration', 'Configuration',
|
|
|
|
ondelete='CASCADE', select=True, required=True)
|
|
|
|
category = fields.Many2One('product.category', 'Category',
|
|
|
|
ondelete='CASCADE', select=True, required=True)
|
|
|
|
|
|
|
|
|
|
|
|
class LabWorkYear(ModelSQL, ModelView, CompanyMultiValueMixin):
|
2017-10-08 02:23:22 +02:00
|
|
|
'Work Year'
|
|
|
|
__name__ = 'lims.lab.workyear'
|
|
|
|
_rec_name = 'code'
|
|
|
|
|
|
|
|
code = fields.Char('Code', required=True)
|
|
|
|
start_date = fields.Date('Start date', required=True)
|
|
|
|
end_date = fields.Date('End date', required=True)
|
|
|
|
entry_sequence = fields.MultiValue(fields.Many2One(
|
2018-05-05 05:36:46 +02:00
|
|
|
'ir.sequence', 'Entry Sequence', required=True,
|
2017-10-08 02:23:22 +02:00
|
|
|
domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_entry')),
|
2017-10-08 02:23:22 +02:00
|
|
|
('company', 'in',
|
|
|
|
[Eval('context', {}).get('company', -1), None]),
|
|
|
|
]))
|
|
|
|
sample_sequence = fields.MultiValue(fields.Many2One(
|
|
|
|
'ir.sequence', 'Sample Sequence', required=True,
|
|
|
|
domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_sample')),
|
2017-10-08 02:23:22 +02:00
|
|
|
('company', 'in',
|
|
|
|
[Eval('context', {}).get('company', -1), None]),
|
|
|
|
]))
|
|
|
|
service_sequence = fields.MultiValue(fields.Many2One(
|
|
|
|
'ir.sequence', 'Service Sequence', required=True,
|
|
|
|
domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_service')),
|
2017-10-08 02:23:22 +02:00
|
|
|
('company', 'in',
|
|
|
|
[Eval('context', {}).get('company', -1), None]),
|
|
|
|
]))
|
|
|
|
results_report_sequence = fields.MultiValue(fields.Many2One(
|
2018-05-05 05:36:46 +02:00
|
|
|
'ir.sequence', 'Results Report Sequence', required=True,
|
2017-10-08 02:23:22 +02:00
|
|
|
domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_results_report')),
|
2017-10-08 02:23:22 +02:00
|
|
|
('company', 'in',
|
|
|
|
[Eval('context', {}).get('company', -1), None]),
|
|
|
|
]))
|
2018-05-05 05:36:46 +02:00
|
|
|
sequences = fields.One2Many('lims.lab.workyear.sequence',
|
|
|
|
'workyear', 'Sequences')
|
|
|
|
default_entry_control = fields.Many2One('lims.entry',
|
|
|
|
'Default entry control')
|
2020-06-18 23:27:08 +02:00
|
|
|
workdays = fields.MultiSelection([
|
|
|
|
(0, 'Monday'),
|
|
|
|
(1, 'Tuesday'),
|
|
|
|
(2, 'Wednesday'),
|
|
|
|
(3, 'Thursday'),
|
|
|
|
(4, 'Friday'),
|
|
|
|
(5, 'Saturday'),
|
|
|
|
(6, 'Sunday'),
|
|
|
|
], 'Working days', sort=False)
|
|
|
|
holidays = fields.One2Many('lims.lab.workyear.holiday', 'workyear',
|
|
|
|
'Holidays')
|
2017-10-08 02:23:22 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def __setup__(cls):
|
2020-08-06 19:52:36 +02:00
|
|
|
super().__setup__()
|
2017-10-08 02:23:22 +02:00
|
|
|
cls._order.insert(0, ('start_date', 'ASC'))
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def multivalue_model(cls, field):
|
|
|
|
pool = Pool()
|
|
|
|
if field in sequence_names:
|
|
|
|
return pool.get('lims.lab.workyear.sequence')
|
2020-08-06 19:52:36 +02:00
|
|
|
return super().multivalue_model(field)
|
2017-10-08 02:23:22 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_entry_sequence(cls, **pattern):
|
|
|
|
return cls.multivalue_model(
|
|
|
|
'entry_sequence').default_entry_sequence()
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_sample_sequence(cls, **pattern):
|
|
|
|
return cls.multivalue_model(
|
|
|
|
'sample_sequence').default_sample_sequence()
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_service_sequence(cls, **pattern):
|
|
|
|
return cls.multivalue_model(
|
|
|
|
'service_sequence').default_service_sequence()
|
|
|
|
|
2020-06-18 23:27:08 +02:00
|
|
|
@staticmethod
|
|
|
|
def default_workdays():
|
|
|
|
return (0, 1, 2, 3, 4)
|
|
|
|
|
2017-10-08 02:23:22 +02:00
|
|
|
@classmethod
|
|
|
|
def validate(cls, years):
|
2020-08-06 19:52:36 +02:00
|
|
|
super().validate(years)
|
2017-10-08 02:23:22 +02:00
|
|
|
for year in years:
|
|
|
|
year.check_dates()
|
|
|
|
|
|
|
|
def check_dates(self):
|
|
|
|
cursor = Transaction().connection.cursor()
|
|
|
|
table = self.__table__()
|
|
|
|
cursor.execute(*table.select(table.id,
|
2018-05-05 05:36:46 +02:00
|
|
|
where=(((table.start_date <= self.start_date) &
|
|
|
|
(table.end_date >= self.start_date)) |
|
|
|
|
((table.start_date <= self.end_date) &
|
|
|
|
(table.end_date >= self.end_date)) |
|
|
|
|
((table.start_date >= self.start_date) &
|
|
|
|
(table.end_date <= self.end_date))) &
|
|
|
|
(table.id != self.id)))
|
2017-10-08 02:23:22 +02:00
|
|
|
second_id = cursor.fetchone()
|
|
|
|
if second_id:
|
|
|
|
second = self.__class__(second_id[0])
|
2019-07-23 23:27:33 +02:00
|
|
|
raise UserError(gettext('lims.msg_workyear_overlaps',
|
|
|
|
first=self.rec_name,
|
|
|
|
second=second.rec_name,
|
|
|
|
))
|
2017-10-08 02:23:22 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def find(cls, date=None, exception=True):
|
|
|
|
pool = Pool()
|
|
|
|
Lang = pool.get('ir.lang')
|
|
|
|
Date = pool.get('ir.date')
|
|
|
|
|
|
|
|
if not date:
|
|
|
|
date = Date.today()
|
|
|
|
workyears = cls.search([
|
|
|
|
('start_date', '<=', date),
|
|
|
|
('end_date', '>=', date),
|
|
|
|
], order=[('start_date', 'DESC')], limit=1)
|
|
|
|
if not workyears:
|
|
|
|
if exception:
|
2019-02-13 13:27:55 +01:00
|
|
|
lang = Lang.get()
|
|
|
|
formatted = lang.strftime(date)
|
2019-07-23 23:27:33 +02:00
|
|
|
raise UserError(gettext(
|
|
|
|
'lims.msg_no_workyear_date', date=formatted))
|
2017-10-08 02:23:22 +02:00
|
|
|
else:
|
|
|
|
return None
|
|
|
|
return workyears[0].id
|
|
|
|
|
|
|
|
def get_sequence(self, type):
|
|
|
|
sequence = getattr(self, type + '_sequence')
|
|
|
|
if sequence:
|
|
|
|
return sequence
|
|
|
|
|
2020-06-19 00:37:14 +02:00
|
|
|
def get_target_date(self, start_date, days):
|
|
|
|
total_days = days + 1 # plus 1 because start_date is included
|
|
|
|
ruleset = rrule.rruleset()
|
|
|
|
|
|
|
|
min_time = datetime.min.time()
|
|
|
|
for h in self.holidays:
|
|
|
|
ruleset.exdate(datetime.combine(h.date, min_time))
|
|
|
|
|
|
|
|
count = total_days
|
|
|
|
ruleset.rrule(rrule.rrule(rrule.DAILY, byweekday=self.workdays,
|
|
|
|
dtstart=start_date, count=count))
|
|
|
|
while(ruleset.count() < total_days): # because holidays subtract days
|
|
|
|
count += 1
|
|
|
|
ruleset.rrule(rrule.rrule(rrule.DAILY, byweekday=self.workdays,
|
|
|
|
dtstart=start_date, count=count))
|
|
|
|
|
|
|
|
return ruleset[-1].date()
|
|
|
|
|
2017-10-08 02:23:22 +02:00
|
|
|
|
2018-05-05 05:36:46 +02:00
|
|
|
class LabWorkYearSequence(ModelSQL, CompanyValueMixin):
|
2017-10-08 02:23:22 +02:00
|
|
|
'Work Year Sequence'
|
|
|
|
__name__ = 'lims.lab.workyear.sequence'
|
|
|
|
|
|
|
|
workyear = fields.Many2One('lims.lab.workyear', 'Work Year',
|
|
|
|
ondelete='CASCADE', select=True)
|
2018-05-05 05:36:46 +02:00
|
|
|
entry_sequence = fields.Many2One('ir.sequence',
|
2017-10-08 02:23:22 +02:00
|
|
|
'Entry Sequence', depends=['company'], domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_entry')),
|
2017-10-08 02:23:22 +02:00
|
|
|
('company', 'in', [Eval('company', -1), None]),
|
|
|
|
])
|
|
|
|
sample_sequence = fields.Many2One('ir.sequence',
|
|
|
|
'Sample Sequence', depends=['company'], domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_sample')),
|
2017-10-08 02:23:22 +02:00
|
|
|
('company', 'in', [Eval('company', -1), None]),
|
|
|
|
])
|
|
|
|
service_sequence = fields.Many2One('ir.sequence',
|
|
|
|
'Service Sequence', depends=['company'], domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_service')),
|
2017-10-08 02:23:22 +02:00
|
|
|
('company', 'in', [Eval('company', -1), None]),
|
|
|
|
])
|
2018-05-05 05:36:46 +02:00
|
|
|
results_report_sequence = fields.Many2One('ir.sequence',
|
2017-10-08 02:23:22 +02:00
|
|
|
'Results Report Sequence', depends=['company'], domain=[
|
2021-09-23 00:59:40 +02:00
|
|
|
('sequence_type', '=',
|
|
|
|
Id('lims', 'seq_type_results_report')),
|
2017-10-08 02:23:22 +02:00
|
|
|
('company', 'in', [Eval('company', -1), None]),
|
|
|
|
])
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_entry_sequence(cls):
|
|
|
|
pool = Pool()
|
|
|
|
ModelData = pool.get('ir.model.data')
|
|
|
|
try:
|
|
|
|
return ModelData.get_id('lims.entry', 'seq_entry')
|
|
|
|
except KeyError:
|
|
|
|
return None
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_sample_sequence(cls):
|
|
|
|
pool = Pool()
|
|
|
|
ModelData = pool.get('ir.model.data')
|
|
|
|
try:
|
|
|
|
return ModelData.get_id('lims.sample', 'seq_sample')
|
|
|
|
except KeyError:
|
|
|
|
return None
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_service_sequence(cls):
|
|
|
|
pool = Pool()
|
|
|
|
ModelData = pool.get('ir.model.data')
|
|
|
|
try:
|
|
|
|
return ModelData.get_id('lims.service', 'seq_service')
|
|
|
|
except KeyError:
|
|
|
|
return None
|
2018-05-18 00:44:57 +02:00
|
|
|
|
|
|
|
|
2020-06-18 23:27:08 +02:00
|
|
|
class LabWorkYearHoliday(ModelSQL, ModelView):
|
|
|
|
'Work Year Holiday'
|
|
|
|
__name__ = 'lims.lab.workyear.holiday'
|
|
|
|
|
|
|
|
workyear = fields.Many2One('lims.lab.workyear', 'Work Year',
|
|
|
|
required=True, ondelete='CASCADE', select=True)
|
|
|
|
name = fields.Char('Name', required=True)
|
|
|
|
date = fields.Date('Date', required=True)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def __setup__(cls):
|
2020-08-06 19:52:36 +02:00
|
|
|
super().__setup__()
|
2020-06-18 23:27:08 +02:00
|
|
|
cls._order.insert(0, ('date', 'ASC'))
|
|
|
|
|
|
|
|
|
2019-07-23 23:27:33 +02:00
|
|
|
class Cron(metaclass=PoolMeta):
|
|
|
|
__name__ = 'ir.cron'
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def __setup__(cls):
|
|
|
|
super().__setup__()
|
|
|
|
cls.method.selection.extend([
|
|
|
|
('lims.entry|cron_acknowledgment_of_receipt',
|
|
|
|
"Lims Acknowledgment of Receipt (Samples)"),
|
|
|
|
('lims.fraction|confirm_waiting_fractions',
|
|
|
|
"Lims Confirm Waiting Entries"),
|
|
|
|
('lims.planification|process_waiting_planifications',
|
|
|
|
"Lims Process Waiting Planification"),
|
2020-07-08 02:35:40 +02:00
|
|
|
('lims.trend.chart|clean',
|
|
|
|
"Lims Clean Inactive Trend Charts"),
|
2019-07-23 23:27:33 +02:00
|
|
|
])
|