Migrate to Tryton 4.8
This commit is contained in:
parent
30f3a183df
commit
1630b66fbb
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -2248,7 +2248,6 @@ class CreateAnalysisProduct(Wizard):
|
|||
Template = pool.get('product.template')
|
||||
TemplateCategory = pool.get('product.template-product.category')
|
||||
Uom = pool.get('product.uom')
|
||||
# Distribution = pool.get('analytic_account.distribution')
|
||||
Lang = pool.get('ir.lang')
|
||||
Config = pool.get('lims.configuration')
|
||||
|
||||
|
@ -2278,18 +2277,6 @@ class CreateAnalysisProduct(Wizard):
|
|||
template.account_category = config_.analysis_product_category.id
|
||||
template.accounts_category = True
|
||||
|
||||
if analysis.behavior != 'additional':
|
||||
if analysis.type != 'group':
|
||||
laboratory = analysis.laboratories[0].laboratory
|
||||
else:
|
||||
laboratory = analysis.included_analysis[0].laboratory
|
||||
|
||||
# analytic_distribution = Distribution.search([
|
||||
# ('code', '=', laboratory.code),
|
||||
# ])
|
||||
# if analytic_distribution:
|
||||
# template.analytic_distribution = analytic_distribution[0]
|
||||
|
||||
template.save()
|
||||
|
||||
template_category = TemplateCategory()
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
# 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.
|
||||
|
||||
from .lims_report import *
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2015-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2015-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2015-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .lims import *
|
||||
from .stock import *
|
||||
from . import lims
|
||||
from . import stock
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
Location,
|
||||
Move,
|
||||
lims.Location,
|
||||
stock.Move,
|
||||
module='lims_analytic', type_='model')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[tryton]
|
||||
version=4.4.0
|
||||
version=4.8.0
|
||||
depends:
|
||||
lims
|
||||
analytic_account
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2015-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2015-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2015 Bruno M. Villasanti <bvillasanti@thymbra.com>
|
||||
Copyright (C) 2015-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
|
|
|
@ -3,21 +3,21 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .configuration import *
|
||||
from .lims import *
|
||||
from wizard import *
|
||||
from . import configuration
|
||||
from . import lims
|
||||
from . import digital_sign
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
LimsConfiguration,
|
||||
LimsResultsReportVersionDetail,
|
||||
LimsResultsReport,
|
||||
DigitalSignStart,
|
||||
DigitalSignSucceed,
|
||||
DigitalSignFailed,
|
||||
configuration.Configuration,
|
||||
lims.ResultsReportVersionDetail,
|
||||
lims.ResultsReport,
|
||||
digital_sign.DigitalSignStart,
|
||||
digital_sign.DigitalSignSucceed,
|
||||
digital_sign.DigitalSignFailed,
|
||||
module='lims_digital_sign', type_='model')
|
||||
Pool.register(
|
||||
LimsResultsReportAnnulation,
|
||||
DigitalSign,
|
||||
lims.ResultsReportAnnulation,
|
||||
digital_sign.DigitalSign,
|
||||
module='lims_digital_sign', type_='wizard')
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
from trytond.model import fields
|
||||
from trytond.pool import PoolMeta
|
||||
|
||||
__all__ = ['LimsConfiguration']
|
||||
__all__ = ['Configuration']
|
||||
|
||||
|
||||
class LimsConfiguration:
|
||||
class Configuration:
|
||||
__name__ = 'lims.configuration'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
|
@ -9,8 +9,8 @@ from trytond.model import ModelView, fields
|
|||
from trytond.wizard import Wizard, StateView, StateTransition, Button
|
||||
from trytond.pool import Pool
|
||||
from trytond.transaction import Transaction
|
||||
from ..lims import HAS_PDFMERGER
|
||||
from ..lims import HAS_TOKEN
|
||||
from .lims import HAS_PDFMERGER
|
||||
from .lims import HAS_TOKEN
|
||||
|
||||
__all__ = ['DigitalSignStart', 'DigitalSignSucceed', 'DigitalSignFailed',
|
||||
'DigitalSign']
|
||||
|
@ -61,19 +61,19 @@ class DigitalSign(Wizard):
|
|||
'''
|
||||
logger = logging.getLogger('lims_digital_sign')
|
||||
logger.info('Wizard - Digital Sign:INIT')
|
||||
LimsResultsReport = Pool().get('lims.results_report')
|
||||
ResultsReport = Pool().get('lims.results_report')
|
||||
|
||||
if not HAS_PDFMERGER:
|
||||
LimsResultsReport.raise_user_error('missing_module')
|
||||
ResultsReport.raise_user_error('missing_module')
|
||||
if not HAS_TOKEN:
|
||||
LimsResultsReport.raise_user_error('missing_module_token')
|
||||
ResultsReport.raise_user_error('missing_module_token')
|
||||
|
||||
context = Transaction().context
|
||||
model = context.get('active_model', None)
|
||||
if model and model == 'ir.ui.menu':
|
||||
# If it was executed from `menu item`, then get ids
|
||||
# TODO: Include signed but not sent?
|
||||
active_ids = [r.id for r in LimsResultsReport.search([
|
||||
active_ids = [r.id for r in ResultsReport.search([
|
||||
('signed', '=', False)])]
|
||||
logger.info('Wizard - Digital Sign:Processing all Results '
|
||||
'Reports')
|
||||
|
@ -86,7 +86,7 @@ class DigitalSign(Wizard):
|
|||
unsigned_reports = []
|
||||
unsent_reports = []
|
||||
for active_id in active_ids:
|
||||
results_report = LimsResultsReport(active_id)
|
||||
results_report = ResultsReport(active_id)
|
||||
logger.info('Wizard - Digital Sign:results_report.number:%s',
|
||||
results_report.number)
|
||||
if (results_report.single_sending_report and not
|
|
@ -0,0 +1,121 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Groups -->
|
||||
|
||||
<record model="res.group" id="group_lims_digital_sign">
|
||||
<field name="name">Lims Digital Sign</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lims_digital_sign">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<!-- Users -->
|
||||
|
||||
<record model="res.user" id="user_digital_sign">
|
||||
<field name="login">user_cron_digital_sign</field>
|
||||
<field name="name">Cron Lims Digital Sign</field>
|
||||
<field name="signature"></field>
|
||||
<field name="active" eval="False"/>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_digital_sign_group_digital_sign">
|
||||
<field name="user" ref="user_digital_sign"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<!-- Cron -->
|
||||
|
||||
<record model="ir.cron" id="cron_lims_digital_sign_results_reports">
|
||||
<field name="name">Lims Digital Sign Results Reports</field>
|
||||
<field name="request_user" ref="res.user_admin"/>
|
||||
<field name="user" ref="user_digital_sign"/>
|
||||
<field name="active" eval="True"/>
|
||||
<field name="interval_number" eval="1"/>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="number_calls" eval="-1"/>
|
||||
<field name="repeat_missed" eval="False"/>
|
||||
<field name="model">lims.results_report</field>
|
||||
<field name="function">cron_digital_signs</field>
|
||||
</record>
|
||||
|
||||
<!-- Wizard Digital Sign -->
|
||||
|
||||
<record model="ir.ui.view" id="view_digital_sign_start">
|
||||
<field name="model">lims_digital_sign.digital_sign.start</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">digital_sign_start_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_digital_sign_succeed">
|
||||
<field name="model">lims_digital_sign.digital_sign.succeed</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">digital_sign_succeed_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_digital_sign_failed">
|
||||
<field name="model">lims_digital_sign.digital_sign.failed</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">digital_sign_failed_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.wizard" id="wizard_digital_sign">
|
||||
<field name="name">Digital Sign</field>
|
||||
<field name="wiz_name">lims_digital_sign.digital_sign</field>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="wizard_digital_sign_keyword">
|
||||
<field name="keyword">form_action</field>
|
||||
<field name="model">lims.results_report,-1</field>
|
||||
<field name="action" ref="wizard_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<!-- Access Rights on Menu -->
|
||||
|
||||
<!-- Laboratory / Results reports / Digital Sign -->
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_laboratory_group_digital_sign">
|
||||
<field name="menu" ref="lims.lims_laboratory"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_laboratory_reports_group_digital_sign">
|
||||
<field name="menu" ref="lims.lims_laboratory_reports"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<!-- Access Rights on Actions -->
|
||||
|
||||
<record model="ir.action-res.group" id="wizard_digital_sign_group_digital_sign">
|
||||
<field name="action" ref="wizard_digital_sign"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<!-- Lims -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_results_report_view_list">
|
||||
<field name="model">lims.results_report</field>
|
||||
<field name="inherit" ref="lims.lims_results_report_view_list"/>
|
||||
<field name="name">results_report_list</field>
|
||||
</record>
|
||||
|
||||
<!-- Icons -->
|
||||
|
||||
<record model="ir.ui.icon" id="digital_sign_icon">
|
||||
<field name="name">lims-digital_sign</field>
|
||||
<field name="path">icons/digital_sign.svg</field>
|
||||
</record>
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<!-- Laboratory / Results reports / Digital Sign -->
|
||||
<menuitem parent="lims.lims_laboratory_reports" action="wizard_digital_sign"
|
||||
id="menu_digital_sign" sequence="40"
|
||||
icon="lims-digital_sign"/>
|
||||
<record model="ir.ui.menu-res.group" id="menu_digital_sign_group_digital_sign">
|
||||
<field name="menu" ref="menu_digital_sign"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Cron -->
|
||||
|
||||
<record model="ir.cron" id="cron_lims_digital_sign_results_reports">
|
||||
<field name="name">Lims Digital Sign Results Reports</field>
|
||||
<field name="request_user" ref="res.user_admin"/>
|
||||
<field name="user" ref="user_digital_sign"/>
|
||||
<field name="active" eval="True"/>
|
||||
<field name="interval_number" eval="1"/>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="number_calls" eval="-1"/>
|
||||
<field name="repeat_missed" eval="False"/>
|
||||
<field name="model">lims.results_report</field>
|
||||
<field name="function">cron_digital_signs</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -19,7 +19,8 @@ from trytond.transaction import Transaction
|
|||
from trytond.tools import get_smtp_server
|
||||
from trytond.config import config as tconfig
|
||||
|
||||
__all__ = ['LimsResultsReportVersionDetail', 'LimsResultsReport']
|
||||
__all__ = ['ResultsReportVersionDetail', 'ResultsReport',
|
||||
'ResultsReportAnnulation']
|
||||
|
||||
HAS_PDFMERGER = False
|
||||
try:
|
||||
|
@ -42,7 +43,7 @@ except ImportError:
|
|||
exc_info=True)
|
||||
|
||||
|
||||
class LimsResultsReportVersionDetail:
|
||||
class ResultsReportVersionDetail:
|
||||
__name__ = 'lims.results_report.version.detail'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -62,19 +63,19 @@ class LimsResultsReportVersionDetail:
|
|||
@classmethod
|
||||
@ModelView.button
|
||||
def revise(cls, details):
|
||||
super(LimsResultsReportVersionDetail, cls).revise(details)
|
||||
super(ResultsReportVersionDetail, cls).revise(details)
|
||||
for detail in details:
|
||||
detail.unsign()
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
def revise_all_lang(cls, details):
|
||||
super(LimsResultsReportVersionDetail, cls).revise_all_lang(details)
|
||||
super(ResultsReportVersionDetail, cls).revise_all_lang(details)
|
||||
for detail in details:
|
||||
detail.unsign()
|
||||
|
||||
|
||||
class LimsResultsReport:
|
||||
class ResultsReport:
|
||||
__name__ = 'lims.results_report'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -85,7 +86,7 @@ class LimsResultsReport:
|
|||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(LimsResultsReport, cls).__setup__()
|
||||
super(ResultsReport, cls).__setup__()
|
||||
cls._error_messages.update({
|
||||
'missing_module_token': 'Missing tokenclient module',
|
||||
'polisample': 'Polisample',
|
||||
|
@ -93,7 +94,7 @@ class LimsResultsReport:
|
|||
|
||||
@classmethod
|
||||
def _get_modified_fields(cls):
|
||||
fields = super(LimsResultsReport, cls)._get_modified_fields()
|
||||
fields = super(ResultsReport, cls)._get_modified_fields()
|
||||
fields.extend([
|
||||
'signed',
|
||||
'signed_date',
|
||||
|
@ -110,16 +111,16 @@ class LimsResultsReport:
|
|||
logging.getLogger('lims_digital_sign').info(
|
||||
'Cron - Digital Signs:INIT')
|
||||
pool = Pool()
|
||||
LimsResultsReport = pool.get('lims.results_report')
|
||||
ResultsReport = pool.get('lims.results_report')
|
||||
DigitalSign = pool.get('lims_digital_sign.digital_sign', type='wizard')
|
||||
|
||||
if not HAS_PDFMERGER:
|
||||
LimsResultsReport.raise_user_error('missing_module')
|
||||
ResultsReport.raise_user_error('missing_module')
|
||||
if not HAS_TOKEN:
|
||||
LimsResultsReport.raise_user_error('missing_module_token')
|
||||
ResultsReport.raise_user_error('missing_module_token')
|
||||
|
||||
results_reports = LimsResultsReport.search([
|
||||
('signed', '=', False)]) # TODO: Include signed but not sent?
|
||||
results_reports = ResultsReport.search([
|
||||
('signed', '=', False)])
|
||||
|
||||
session_id, _, _ = DigitalSign.create()
|
||||
digital_sign = DigitalSign(session_id)
|
||||
|
@ -149,13 +150,13 @@ class LimsResultsReport:
|
|||
:return: list of details
|
||||
'''
|
||||
pool = Pool()
|
||||
LimsResultsReportVersionDetail = pool.get(
|
||||
ResultsReportVersionDetail = pool.get(
|
||||
'lims.results_report.version.detail')
|
||||
|
||||
format_field = 'report_format'
|
||||
if english_report:
|
||||
format_field = 'report_format_eng'
|
||||
details = LimsResultsReportVersionDetail.search([
|
||||
details = ResultsReportVersionDetail.search([
|
||||
('report_version.results_report.id', '=', self.id),
|
||||
('valid', '=', True),
|
||||
(format_field, '=', 'pdf'),
|
||||
|
@ -247,8 +248,8 @@ class LimsResultsReport:
|
|||
for line in detail.notebook_lines:
|
||||
to_addrs.extend([c.contact.email for c
|
||||
in line.notebook_line.fraction.entry.report_contacts
|
||||
if c.contact.report_contact
|
||||
and not c.entry.invoice_party.block_reports_automatic_sending])
|
||||
if c.contact.report_contact and not
|
||||
c.entry.invoice_party.block_reports_automatic_sending])
|
||||
entries.append(line.notebook_line.fraction.entry.number) # TODO: Debug line
|
||||
logging.getLogger('lims_digital_sign').info(
|
||||
'Cron - Digital Signs:results_report.number:%s:to_addrs:%s'
|
||||
|
@ -322,12 +323,14 @@ class LimsResultsReport:
|
|||
def attachment(self, english_report=False):
|
||||
suffix = 'eng' if english_report else 'esp'
|
||||
data = {
|
||||
'content': (english_report
|
||||
and self.report_cache_eng
|
||||
or self.report_cache),
|
||||
'format': (english_report
|
||||
and self.report_format_eng
|
||||
or self.report_format),
|
||||
'content': (
|
||||
english_report and
|
||||
self.report_cache_eng or
|
||||
self.report_cache),
|
||||
'format': (
|
||||
english_report and
|
||||
self.report_format_eng or
|
||||
self.report_format),
|
||||
'mimetype': 'pdf',
|
||||
'filename': unicode(self.number) + '-' + suffix + '.pdf',
|
||||
'name': unicode(self.number),
|
||||
|
@ -341,7 +344,7 @@ class LimsResultsReport:
|
|||
|
||||
msg = MIMEMultipart()
|
||||
msg['From'] = from_addr
|
||||
hidden = True # TODO: HARDCODE!
|
||||
hidden = True
|
||||
if not hidden:
|
||||
msg['To'] = ', '.join(to_addrs)
|
||||
msg['Subject'] = subject
|
||||
|
@ -416,3 +419,41 @@ class LimsResultsReport:
|
|||
if attachment:
|
||||
Attachment.delete(attachment)
|
||||
return True
|
||||
|
||||
|
||||
class ResultsReportAnnulation:
|
||||
__name__ = 'lims.results_report_annulation'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
def transition_annul(self):
|
||||
logging.getLogger('lims_digital_sign').info(
|
||||
'transition_annul():INIT')
|
||||
super(ResultsReportAnnulation, self).transition_annul()
|
||||
logging.getLogger('lims_digital_sign').info(
|
||||
'transition_annul():INHERIT')
|
||||
|
||||
ResultsReportVersionDetail = Pool().get(
|
||||
'lims.results_report.version.detail')
|
||||
|
||||
# Check if the detail was annulled
|
||||
detail_annulled = ResultsReportVersionDetail.search([
|
||||
('id', 'in', Transaction().context['active_ids']),
|
||||
('state', '=', 'annulled'),
|
||||
])
|
||||
for detail in detail_annulled:
|
||||
detail.unsign()
|
||||
|
||||
# Check if the report is not longer valid details
|
||||
if detail_annulled:
|
||||
results_report = detail_annulled[0].report_version.results_report
|
||||
detail_valid = ResultsReportVersionDetail.search([
|
||||
('report_version.results_report.id', '=', results_report.id),
|
||||
('state', '!=', 'annulled'),
|
||||
('valid', '=', True),
|
||||
])
|
||||
if not detail_valid:
|
||||
results_report.clean_attachments_reports()
|
||||
|
||||
logging.getLogger('lims_digital_sign').info(
|
||||
'transition_annul():END')
|
||||
return 'end'
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Icons -->
|
||||
|
||||
<record model="ir.ui.icon" id="digital_sign_icon">
|
||||
<field name="name">lims-digital_sign</field>
|
||||
<field name="path">icons/digital_sign.svg</field>
|
||||
</record>
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<!-- Laboratory / Results reports / Digital Sign -->
|
||||
<menuitem parent="lims.lims_laboratory_reports" action="wizard_digital_sign"
|
||||
id="menu_digital_sign" sequence="40"
|
||||
icon="lims-digital_sign"/>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Lims -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_results_report_view_list">
|
||||
<field name="model">lims.results_report</field>
|
||||
<field name="inherit" ref="lims.lims_results_report_view_list"/>
|
||||
<field name="name">results_report_list</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,39 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Access Rights on Menu -->
|
||||
|
||||
<!-- Laboratory / Results reports / Digital Sign -->
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_group_digital_sign">
|
||||
<field name="menu" ref="lims.lims_menu"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_laboratory_group_digital_sign">
|
||||
<field name="menu" ref="lims.lims_laboratory"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_laboratory_reports_group_digital_sign">
|
||||
<field name="menu" ref="lims.lims_laboratory_reports"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_digital_sign_group_digital_sign">
|
||||
<field name="menu" ref="menu_digital_sign"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<!-- Access Rights on Actions -->
|
||||
|
||||
<record model="ir.action-res.group" id="wizard_digital_sign_group_digital_sign">
|
||||
<field name="action" ref="wizard_digital_sign"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,31 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Groups -->
|
||||
|
||||
<record model="res.group" id="group_lims_digital_sign">
|
||||
<field name="name">Lims Digital Sign</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lims_digital_sign">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
<!-- Users -->
|
||||
|
||||
<record model="res.user" id="user_digital_sign">
|
||||
<field name="login">user_cron_digital_sign</field>
|
||||
<field name="name">Cron Lims Digital Sign</field>
|
||||
<field name="signature"></field>
|
||||
<field name="active" eval="False"/>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_digital_sign_group_digital_sign">
|
||||
<field name="user" ref="user_digital_sign"/>
|
||||
<field name="group" ref="group_lims_digital_sign"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,12 +1,7 @@
|
|||
[tryton]
|
||||
version=4.4.0
|
||||
version=4.8.0
|
||||
depends:
|
||||
lims
|
||||
xml:
|
||||
security/users.xml
|
||||
digital_sign_view.xml
|
||||
configuration_view.xml
|
||||
lims_view.xml
|
||||
wizard/digital_sign.xml
|
||||
lims_menu.xml
|
||||
security/access_rights.xml
|
||||
digital_sign.xml
|
||||
configuration.xml
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# This file is part of lims_digital_sign module for Tryton.
|
||||
# The COPYRIGHT file at the top level of this repository contains
|
||||
# the full copyright notices and license terms.
|
||||
|
||||
from .digital_sign import *
|
||||
from .lims import *
|
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Menu items in lims_menu.xml -->
|
||||
|
||||
<!-- Wizard Digital Sign -->
|
||||
|
||||
<record model="ir.ui.view" id="view_digital_sign_start">
|
||||
<field name="model">lims_digital_sign.digital_sign.start</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">digital_sign_start_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_digital_sign_succeed">
|
||||
<field name="model">lims_digital_sign.digital_sign.succeed</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">digital_sign_succeed_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_digital_sign_failed">
|
||||
<field name="model">lims_digital_sign.digital_sign.failed</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">digital_sign_failed_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.wizard" id="wizard_digital_sign">
|
||||
<field name="name">Digital Sign</field>
|
||||
<field name="wiz_name">lims_digital_sign.digital_sign</field>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="wizard_digital_sign_keyword">
|
||||
<field name="keyword">form_action</field>
|
||||
<field name="model">lims.results_report,-1</field>
|
||||
<field name="action" ref="wizard_digital_sign"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,48 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# This file is part of lims_digital_sign module for Tryton.
|
||||
# The COPYRIGHT file at the top level of this repository contains
|
||||
# the full copyright notices and license terms.
|
||||
import logging
|
||||
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
__all__ = ['LimsResultsReportAnnulation']
|
||||
|
||||
|
||||
class LimsResultsReportAnnulation:
|
||||
__name__ = 'lims.results_report_annulation'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
def transition_annul(self):
|
||||
logging.getLogger('lims_digital_sign').info(
|
||||
'transition_annul():INIT')
|
||||
super(LimsResultsReportAnnulation, self).transition_annul()
|
||||
logging.getLogger('lims_digital_sign').info(
|
||||
'transition_annul():INHERIT')
|
||||
|
||||
LimsResultsReportVersionDetail = Pool().get(
|
||||
'lims.results_report.version.detail')
|
||||
|
||||
# Check if the detail was annulled
|
||||
detail_annulled = LimsResultsReportVersionDetail.search([
|
||||
('id', 'in', Transaction().context['active_ids']),
|
||||
('state', '=', 'annulled'),
|
||||
])
|
||||
for detail in detail_annulled:
|
||||
detail.unsign()
|
||||
|
||||
# Check if the report is not longer valid details
|
||||
if detail_annulled:
|
||||
results_report = detail_annulled[0].report_version.results_report
|
||||
detail_valid = LimsResultsReportVersionDetail.search([
|
||||
('report_version.results_report.id', '=', results_report.id),
|
||||
('state', '!=', 'annulled'),
|
||||
('valid', '=', True),
|
||||
])
|
||||
if not detail_valid:
|
||||
results_report.clean_attachments_reports()
|
||||
|
||||
logging.getLogger('lims_digital_sign').info(
|
||||
'transition_annul():END')
|
||||
return 'end'
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2013-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -3,21 +3,20 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .resultsimport import *
|
||||
from wizard import *
|
||||
from . import resultsimport
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
LimsNotebookLine,
|
||||
LimsResultsImport,
|
||||
LimsNotebookLoadResultsFileStart,
|
||||
LimsNotebookLoadResultsFileStartLine,
|
||||
LimsNotebookLoadResultsFileEmpty,
|
||||
LimsNotebookLoadResultsFileResult,
|
||||
LimsNotebookLoadResultsFileWarning,
|
||||
LimsNotebookLoadResultsFileExport,
|
||||
resultsimport.NotebookLine,
|
||||
resultsimport.ResultsImport,
|
||||
resultsimport.NotebookLoadResultsFileStart,
|
||||
resultsimport.NotebookLoadResultsFileStartLine,
|
||||
resultsimport.NotebookLoadResultsFileEmpty,
|
||||
resultsimport.NotebookLoadResultsFileResult,
|
||||
resultsimport.NotebookLoadResultsFileWarning,
|
||||
resultsimport.NotebookLoadResultsFileExport,
|
||||
module='lims_instrument', type_='model')
|
||||
Pool.register(
|
||||
LimsNotebookLoadResultsFile,
|
||||
resultsimport.NotebookLoadResultsFile,
|
||||
module='lims_instrument', type_='wizard')
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
Módulo Lims Instrument
|
||||
######################
|
||||
|
||||
Este módulo define la base para poder agregar importadores de resultados.
|
||||
Un importador de resultados es un proceso capaz de leer determinado tipo de
|
||||
archivo, extraer información e importarla en el sistema.
|
||||
Los archivos que se procesan son usualmente de tipo CSV o XLS, generados por
|
||||
instrumentos o equipos de laboratorio a partir de pruebas realizadas.
|
||||
|
||||
|
||||
Importadores de resultados
|
||||
**************************
|
||||
|
||||
En Lims > Configuración > Importadores de resultados se pueden definir y
|
||||
listar un importador de resultados.
|
||||
Estos importadores se definen en módulos específicos, que extienden a este.
|
||||
|
||||
|
||||
Asistente para carga de resultados desde archivo
|
||||
********************************************
|
||||
|
||||
Desde Lims > Laboratorio > Ingreso de resultados > Carga de resultados desde
|
||||
archivo se puede lanzar el asistente de importación.
|
||||
|
||||
Es necesario definir un Importador de resultados y un archivo a ser importado.
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Icons -->
|
||||
|
||||
<record model="ir.ui.icon" id="notebook_load_results_file_icon">
|
||||
<field name="name">lims-notebook_load_results_file</field>
|
||||
<field name="path">icons/notebook_load_results_file.svg</field>
|
||||
</record>
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<!-- Configuration / Laboratory / Results Importers -->
|
||||
<menuitem parent="lims.lims_config_laboratory" action="act_lims_resultsimport_list"
|
||||
id="lims_resultsimport_menu" sequence="60"/>
|
||||
|
||||
<!-- Laboratory / Results entry / Load Results from File -->
|
||||
<menuitem parent="lims.lims_laboratory_results" action="wiz_lims_notebook_load_results_file"
|
||||
id="lims_notebook_load_results_file_menu" sequence="30"
|
||||
icon="lims-notebook_load_results_file"/>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -2,15 +2,28 @@
|
|||
# This file is part of lims_instrument module for Tryton.
|
||||
# The COPYRIGHT file at the top level of this repository contains
|
||||
# the full copyright notices and license terms.
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
import traceback
|
||||
import xlrd
|
||||
from xlutils.copy import copy
|
||||
from datetime import datetime
|
||||
|
||||
from trytond.model import ModelView, ModelSQL, fields, Unique
|
||||
from trytond.pool import PoolMeta
|
||||
|
||||
__all__ = ['LimsNotebookLine', 'LimsResultsImport']
|
||||
from trytond.wizard import Wizard, StateView, StateTransition, Button
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class LimsNotebookLine:
|
||||
__all__ = ['NotebookLine', 'ResultsImport', 'NotebookLoadResultsFileStart',
|
||||
'NotebookLoadResultsFileStartLine', 'NotebookLoadResultsFileEmpty',
|
||||
'NotebookLoadResultsFileResult', 'NotebookLoadResultsFileWarning',
|
||||
'NotebookLoadResultsFileExport', 'NotebookLoadResultsFile']
|
||||
|
||||
|
||||
class NotebookLine:
|
||||
__name__ = 'lims.notebook.line'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -24,7 +37,7 @@ class LimsNotebookLine:
|
|||
imported_rm_correction_formula = fields.Char('RM Correction Formula')
|
||||
|
||||
|
||||
class LimsResultsImport(ModelSQL, ModelView):
|
||||
class ResultsImport(ModelSQL, ModelView):
|
||||
'Results Import'
|
||||
__name__ = 'lims.resultsimport'
|
||||
_rec_name = 'description'
|
||||
|
@ -41,7 +54,7 @@ class LimsResultsImport(ModelSQL, ModelView):
|
|||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(LimsResultsImport, cls).__setup__()
|
||||
super(ResultsImport, cls).__setup__()
|
||||
t = cls.__table__()
|
||||
cls._sql_constraints += [
|
||||
('name_uniq', Unique(t, t.name),
|
||||
|
@ -96,3 +109,409 @@ class LimsResultsImport(ModelSQL, ModelView):
|
|||
return self.controller.exportResults(self)
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
|
||||
class NotebookLoadResultsFileStart(ModelView):
|
||||
'Load Results from File'
|
||||
__name__ = 'lims.notebook.load_results_file.start'
|
||||
|
||||
results_importer = fields.Many2One('lims.resultsimport',
|
||||
'Results importer', required=True)
|
||||
lines = fields.One2Many('lims.notebook.load_results_file.start.line',
|
||||
None, 'Files', required=True)
|
||||
|
||||
|
||||
class NotebookLoadResultsFileStartLine(ModelView):
|
||||
'Load Results from File'
|
||||
__name__ = 'lims.notebook.load_results_file.start.line'
|
||||
|
||||
infile = fields.Binary('File', required=True, filename='name')
|
||||
name = fields.Char('Name', readonly=True)
|
||||
|
||||
|
||||
class NotebookLoadResultsFileEmpty(ModelView):
|
||||
'Load Results from File Empty'
|
||||
__name__ = 'lims.notebook.load_results_file.empty'
|
||||
|
||||
|
||||
class NotebookLoadResultsFileResult(ModelView):
|
||||
'Process Results from File'
|
||||
__name__ = 'lims.notebook.load_results_file.result'
|
||||
|
||||
result_lines = fields.One2Many('lims.notebook.line', None, 'Lines',
|
||||
readonly=True)
|
||||
|
||||
|
||||
class NotebookLoadResultsFileWarning(ModelView):
|
||||
'Load Results from File Warning'
|
||||
__name__ = 'lims.notebook.load_results_file.warning'
|
||||
|
||||
msg = fields.Text('Message')
|
||||
|
||||
|
||||
class NotebookLoadResultsFileExport(ModelView):
|
||||
"Export Results from File"
|
||||
__name__ = 'lims.notebook.load_results_file.export'
|
||||
|
||||
file = fields.Binary('File', readonly=True)
|
||||
|
||||
|
||||
class NotebookLoadResultsFile(Wizard):
|
||||
'Load Results from File'
|
||||
__name__ = 'lims.notebook.load_results_file'
|
||||
|
||||
start = StateView('lims.notebook.load_results_file.start',
|
||||
'lims_instrument.lims_load_results_file_start_view_form', [
|
||||
Button('Cancel', 'end', 'tryton-cancel'),
|
||||
Button('Collect', 'collect', 'tryton-go-next', default=True),
|
||||
])
|
||||
collect = StateTransition()
|
||||
empty = StateView('lims.notebook.load_results_file.empty',
|
||||
'lims_instrument.lims_load_results_file_empty_view_form', [
|
||||
Button('Try again', 'start', 'tryton-go-next'),
|
||||
Button('Close', 'end', 'tryton-close', default=True),
|
||||
])
|
||||
result = StateView('lims.notebook.load_results_file.result',
|
||||
'lims_instrument.lims_load_results_file_result_view_form', [
|
||||
Button('Cancel', 'cancel', 'tryton-cancel'),
|
||||
Button('Confirm', 'confirm', 'tryton-ok', default=True),
|
||||
])
|
||||
confirm = StateTransition()
|
||||
cancel = StateTransition()
|
||||
warning = StateView('lims.notebook.load_results_file.warning',
|
||||
'lims_instrument.lims_load_results_file_warning_view_form', [
|
||||
Button('Ok', 'close', 'tryton-ok'),
|
||||
])
|
||||
close = StateTransition()
|
||||
export = StateView('lims.notebook.load_results_file.export',
|
||||
'lims_instrument.lims_load_results_file_export_view_form', [
|
||||
Button('Done', 'end', 'tryton-close', default=True),
|
||||
])
|
||||
|
||||
def transition_collect(self):
|
||||
cursor = Transaction().connection.cursor()
|
||||
pool = Pool()
|
||||
Fraction = pool.get('lims.fraction')
|
||||
Notebook = pool.get('lims.notebook')
|
||||
NotebookLine = pool.get('lims.notebook.line')
|
||||
Analysis = pool.get('lims.analysis')
|
||||
|
||||
lines = []
|
||||
for fline in self.start.lines:
|
||||
self.start.results_importer.rawresults = {}
|
||||
self.start.results_importer.parse(fline.infile)
|
||||
raw_results = self.start.results_importer.rawresults
|
||||
fractions_numbers = list(raw_results.keys())
|
||||
if not fractions_numbers:
|
||||
continue
|
||||
|
||||
numbers = '\', \''.join(str(n) for n in fractions_numbers)
|
||||
cursor.execute('SELECT id, number '
|
||||
'FROM "' + Fraction._table + '" '
|
||||
'WHERE number IN (\'' + numbers + '\') '
|
||||
'ORDER BY number ASC')
|
||||
|
||||
for f in cursor.fetchall():
|
||||
cursor.execute('SELECT id '
|
||||
'FROM "' + Notebook._table + '" '
|
||||
'WHERE fraction = %s '
|
||||
'LIMIT 1', (f[0],))
|
||||
notebook = cursor.fetchone()
|
||||
if not notebook:
|
||||
continue
|
||||
|
||||
for analysis in raw_results[f[1]].keys():
|
||||
cursor.execute('SELECT id '
|
||||
'FROM "' + Analysis._table + '" '
|
||||
'WHERE code = %s '
|
||||
'AND automatic_acquisition = TRUE '
|
||||
'LIMIT 1', (analysis,))
|
||||
if not cursor.fetchone():
|
||||
continue
|
||||
|
||||
for rep in raw_results[f[1]][analysis].keys():
|
||||
clause = [
|
||||
('notebook', '=', notebook[0]),
|
||||
('analysis', '=', analysis),
|
||||
('repetition', '=', rep),
|
||||
('result', 'in', [None, '']),
|
||||
('converted_result', 'in', [None, '']),
|
||||
('literal_result', 'in', [None, '']),
|
||||
('result_modifier', 'not in', ['nd', 'pos', 'neg',
|
||||
'ni', 'abs', 'pre', 'na']),
|
||||
('converted_result_modifier', 'not in',
|
||||
['nd', 'pos', 'neg', 'ni', 'abs', 'pre']),
|
||||
]
|
||||
line = NotebookLine.search(clause)
|
||||
if line:
|
||||
data = raw_results[f[1]][analysis][rep]
|
||||
res = self.get_results(line[0], data)
|
||||
if res:
|
||||
NotebookLine.write([line[0]], res)
|
||||
lines.append(line[0])
|
||||
|
||||
if lines:
|
||||
self.result.result_lines = [l.id for l in lines]
|
||||
return 'result'
|
||||
return 'empty'
|
||||
|
||||
def get_results(self, line, data):
|
||||
pool = Pool()
|
||||
Device = pool.get('lims.lab.device')
|
||||
|
||||
res = {}
|
||||
if 'result' in data or 'literal_result' in data:
|
||||
if 'result' in data:
|
||||
res['imported_result'] = unicode(float(data['result']))
|
||||
if 'literal_result' in data:
|
||||
res['imported_literal_result'] = data['literal_result']
|
||||
res['imported_end_date'] = (data['end_date'] if 'end_date' in data
|
||||
else line.end_date)
|
||||
if 'professionals' in data:
|
||||
res['imported_professionals'] = data['professionals']
|
||||
if 'chromatogram' in data:
|
||||
res['imported_chromatogram'] = data['chromatogram']
|
||||
device = data['device'] if 'device' in data else None
|
||||
if device:
|
||||
dev = Device.search([('code', '=', device)])
|
||||
if dev:
|
||||
res['imported_device'] = dev[0].id
|
||||
if 'dilution_factor' in data:
|
||||
res['imported_dilution_factor'] = data['dilution_factor']
|
||||
if 'rm_correction_formula' in data:
|
||||
res['imported_rm_correction_formula'] = (
|
||||
data['rm_correction_formula'])
|
||||
return res
|
||||
|
||||
def default_result(self, fields):
|
||||
default = {}
|
||||
default['result_lines'] = [l.id for l in self.result.result_lines]
|
||||
return default
|
||||
|
||||
def get_professionals(self, professionals_codes):
|
||||
'''
|
||||
This function gets a string with one or more professionals codes,
|
||||
separated by commas, like: 'ABC' or 'JLB, ABC'
|
||||
It returns the professionals
|
||||
'''
|
||||
cursor = Transaction().connection.cursor()
|
||||
pool = Pool()
|
||||
Professional = pool.get('lims.laboratory.professional')
|
||||
|
||||
res = []
|
||||
professionals = ''.join(professionals_codes.split())
|
||||
professionals = professionals.split(',')
|
||||
for professional in professionals:
|
||||
cursor.execute('SELECT id, code '
|
||||
'FROM "' + Professional._table + '" '
|
||||
'WHERE code = %s '
|
||||
'LIMIT 1', (professional,))
|
||||
prof = cursor.fetchone()
|
||||
if prof:
|
||||
res.append(prof)
|
||||
return res
|
||||
|
||||
def check_professionals(self, professionals, method):
|
||||
cursor = Transaction().connection.cursor()
|
||||
pool = Pool()
|
||||
LabProfessionalMethod = pool.get('lims.lab.professional.method')
|
||||
|
||||
validated = False
|
||||
msg = ''
|
||||
for professional in professionals:
|
||||
cursor.execute('SELECT state '
|
||||
'FROM "' + LabProfessionalMethod._table + '" '
|
||||
'WHERE professional = %s '
|
||||
'AND method = %s '
|
||||
'AND type = \'analytical\' '
|
||||
'LIMIT 1', (professional[0], method.id))
|
||||
qualification = cursor.fetchone()
|
||||
if not qualification:
|
||||
validated = False
|
||||
msg += '%s not qualified for method: %s' % (
|
||||
professional[1], method.code)
|
||||
return validated, msg
|
||||
elif qualification[0] == 'training':
|
||||
if not validated:
|
||||
msg += '%s in training for method: %s. ' \
|
||||
'Add qualified professional' % (
|
||||
professional[1], method.code)
|
||||
elif (qualification[0] in ('qualified', 'requalified')):
|
||||
validated = True
|
||||
|
||||
return validated, msg
|
||||
|
||||
def transition_confirm(self):
|
||||
pool = Pool()
|
||||
NotebookLine = pool.get('lims.notebook.line')
|
||||
|
||||
NOW = datetime.now()
|
||||
warnings = False
|
||||
messages = ''
|
||||
# Write Results to Notebook lines
|
||||
for line in self.result.result_lines:
|
||||
notebook_line_write = {
|
||||
'imported_result': None,
|
||||
'imported_literal_result': None,
|
||||
'imported_end_date': None,
|
||||
'imported_professionals': None,
|
||||
'imported_chromatogram': None,
|
||||
'imported_device': None,
|
||||
'imported_dilution_factor': None,
|
||||
'imported_rm_correction_formula': None,
|
||||
}
|
||||
|
||||
prevent_line = False
|
||||
outcome = ''
|
||||
if line.result != line.imported_result:
|
||||
if line.imported_result != '-1000.0':
|
||||
notebook_line_write['result'] = line.imported_result
|
||||
else:
|
||||
notebook_line_write['result'] = None
|
||||
notebook_line_write['result_modifier'] = 'na'
|
||||
notebook_line_write['report'] = False
|
||||
notebook_line_write['annulled'] = True
|
||||
notebook_line_write['annulment_date'] = NOW
|
||||
if line.literal_result != line.imported_literal_result:
|
||||
notebook_line_write['literal_result'] = (
|
||||
line.imported_literal_result)
|
||||
if line.end_date != line.imported_end_date:
|
||||
if line.imported_result != '-1000.0':
|
||||
if (line.start_date and
|
||||
line.start_date <= line.imported_end_date):
|
||||
notebook_line_write['end_date'] = (
|
||||
line.imported_end_date)
|
||||
else:
|
||||
prevent_line = True
|
||||
outcome = 'End date cannot be lower than Start date'
|
||||
else:
|
||||
notebook_line_write['end_date'] = None
|
||||
if line.chromatogram != line.imported_chromatogram:
|
||||
notebook_line_write['chromatogram'] = (
|
||||
line.imported_chromatogram)
|
||||
if line.device != line.imported_device:
|
||||
notebook_line_write['device'] = line.imported_device
|
||||
if line.dilution_factor != line.imported_dilution_factor:
|
||||
notebook_line_write['dilution_factor'] = (
|
||||
line.imported_dilution_factor)
|
||||
if (line.rm_correction_formula !=
|
||||
line.imported_rm_correction_formula):
|
||||
notebook_line_write['rm_correction_formula'] = (
|
||||
line.imported_rm_correction_formula)
|
||||
|
||||
if line.imported_professionals:
|
||||
profs = self.get_professionals(line.imported_professionals)
|
||||
if profs:
|
||||
validated, msg = self.check_professionals(
|
||||
profs, line.method)
|
||||
if validated:
|
||||
professionals = [{'professional': p[0]}
|
||||
for p in profs]
|
||||
notebook_line_write['professionals'] = (
|
||||
[('delete', [p.id for p in line.professionals])]
|
||||
+ [('create', professionals)])
|
||||
else:
|
||||
prevent_line = True
|
||||
outcome = msg
|
||||
else:
|
||||
prevent_line = True
|
||||
outcome = ('Professional(s) with code '
|
||||
+ unicode(line.imported_professionals)
|
||||
+ ' not identified')
|
||||
|
||||
if not prevent_line:
|
||||
try:
|
||||
NotebookLine.write([line], notebook_line_write)
|
||||
except Exception as e:
|
||||
prevent_line = True
|
||||
outcome = unicode(e)
|
||||
original_profs = [{'professional': p.professional}
|
||||
for p in line.professionals]
|
||||
notebook_line_original_values = {
|
||||
'result': line.result,
|
||||
'literal_result': line.literal_result,
|
||||
'end_date': line.end_date,
|
||||
'professionals': (
|
||||
[('delete', [p.id for p in line.professionals])]
|
||||
+ [('create', original_profs,)]),
|
||||
'chromatogram': line.chromatogram,
|
||||
'device': line.device,
|
||||
'dilution_factor': line.dilution_factor,
|
||||
'rm_correction_formula': line.rm_correction_formula,
|
||||
}
|
||||
NotebookLine.write(
|
||||
[line], notebook_line_original_values)
|
||||
else:
|
||||
outcome = 'OK'
|
||||
|
||||
# Update rawresults
|
||||
row_num = 0
|
||||
if self.start.results_importer.exportResults() or prevent_line:
|
||||
rawresults = self.start.results_importer.rawresults
|
||||
number = line.fraction.number
|
||||
if number in rawresults:
|
||||
code = line.analysis.code
|
||||
if code in rawresults[number]:
|
||||
rep = line.repetition
|
||||
if rep in rawresults[number][code]:
|
||||
rawresults[number][code][rep]['outcome'] = outcome
|
||||
row_num = rawresults[number][code][rep][
|
||||
'row_number']
|
||||
|
||||
if prevent_line:
|
||||
warnings = True
|
||||
messages += str(row_num) + ': ' + outcome + '\n'
|
||||
|
||||
if warnings:
|
||||
self.warning.msg = messages
|
||||
return 'warning'
|
||||
else:
|
||||
if self.start.results_importer.exportResults():
|
||||
return 'end' # 'export'
|
||||
return 'end'
|
||||
|
||||
def transition_cancel(self):
|
||||
NotebookLine = Pool().get('lims.notebook.line')
|
||||
# Clean results froms Notebook lines
|
||||
notebook_line_clean = {
|
||||
'imported_result': None,
|
||||
'imported_literal_result': None,
|
||||
'imported_end_date': None,
|
||||
'imported_professionals': None,
|
||||
'imported_chromatogram': None,
|
||||
'imported_device': None,
|
||||
'imported_dilution_factor': None,
|
||||
'imported_rm_correction_formula': None,
|
||||
}
|
||||
NotebookLine.write(
|
||||
list(self.result.result_lines), notebook_line_clean)
|
||||
return 'end'
|
||||
|
||||
def default_warning(self, fields):
|
||||
defaults = {}
|
||||
if self.warning.msg:
|
||||
defaults['msg'] = self.warning.msg
|
||||
return defaults
|
||||
|
||||
def transition_close(self):
|
||||
if self.start.results_importer.exportResults():
|
||||
return 'end' # 'export'
|
||||
return 'end'
|
||||
|
||||
def default_export(self, fields):
|
||||
rawresults = self.start.results_importer.rawresults
|
||||
filedata = StringIO.StringIO(self.start.infile) # TODO: refactoring
|
||||
workbook = xlrd.open_workbook(file_contents=filedata.getvalue(),
|
||||
formatting_info=True)
|
||||
wb_copy = copy(workbook)
|
||||
for fraction in rawresults:
|
||||
for analysis in rawresults[fraction]:
|
||||
for rep in rawresults[fraction][analysis]:
|
||||
repetition = rawresults[fraction][analysis][rep]
|
||||
if 'outcome' in repetition and 'status_cell' in repetition:
|
||||
sheet, row, col = repetition['status_cell']
|
||||
wb_sheet = wb_copy.get_sheet(sheet)
|
||||
wb_sheet.write(row, col, repetition['outcome'])
|
||||
output = StringIO.StringIO()
|
||||
wb_copy.save(output)
|
||||
return {'file': bytearray(output.getvalue())}
|
||||
|
|
|
@ -4,6 +4,34 @@
|
|||
|
||||
<!-- Menu items in lims_menu.xml -->
|
||||
|
||||
<!-- Results Import -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_resultsimport_view_form">
|
||||
<field name="model">lims.resultsimport</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">resultsimport_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_resultsimport_view_list">
|
||||
<field name="model">lims.resultsimport</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">resultsimport_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_lims_resultsimport_list">
|
||||
<field name="name">Results Importers</field>
|
||||
<field name="res_model">lims.resultsimport</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_lims_resultsimport_view_list">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="lims_resultsimport_view_list"/>
|
||||
<field name="act_window" ref="act_lims_resultsimport_list"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_lims_resultsimport_view_form">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="lims_resultsimport_view_form"/>
|
||||
<field name="act_window" ref="act_lims_resultsimport_list"/>
|
||||
</record>
|
||||
|
||||
<!-- Wizard Load Results from File -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_load_results_file_start_view_form">
|
||||
|
@ -47,5 +75,23 @@
|
|||
<field name="wiz_name">lims.notebook.load_results_file</field>
|
||||
</record>
|
||||
|
||||
<!-- Icons -->
|
||||
|
||||
<record model="ir.ui.icon" id="notebook_load_results_file_icon">
|
||||
<field name="name">lims-notebook_load_results_file</field>
|
||||
<field name="path">icons/notebook_load_results_file.svg</field>
|
||||
</record>
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<!-- Configuration / Laboratory / Results Importers -->
|
||||
<menuitem parent="lims.lims_config_laboratory" action="act_lims_resultsimport_list"
|
||||
id="lims_resultsimport_menu" sequence="60"/>
|
||||
|
||||
<!-- Laboratory / Results entry / Load Results from File -->
|
||||
<menuitem parent="lims.lims_laboratory_results" action="wiz_lims_notebook_load_results_file"
|
||||
id="lims_notebook_load_results_file_menu" sequence="30"
|
||||
icon="lims-notebook_load_results_file"/>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,36 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Menu items in lims_menu.xml -->
|
||||
|
||||
<!-- Results Import -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_resultsimport_view_form">
|
||||
<field name="model">lims.resultsimport</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">resultsimport_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_resultsimport_view_list">
|
||||
<field name="model">lims.resultsimport</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">resultsimport_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_lims_resultsimport_list">
|
||||
<field name="name">Results Importers</field>
|
||||
<field name="res_model">lims.resultsimport</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_lims_resultsimport_view_list">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="lims_resultsimport_view_list"/>
|
||||
<field name="act_window" ref="act_lims_resultsimport_list"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_lims_resultsimport_view_form">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="lims_resultsimport_view_form"/>
|
||||
<field name="act_window" ref="act_lims_resultsimport_list"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,8 +1,6 @@
|
|||
[tryton]
|
||||
version=4.4.0
|
||||
version=4.8.0
|
||||
depends:
|
||||
lims
|
||||
xml:
|
||||
resultsimport_view.xml
|
||||
wizard/resultsimport.xml
|
||||
lims_menu.xml
|
||||
resultsimport.xml
|
|
@ -1,5 +0,0 @@
|
|||
# This file is part of lims_instrument module for Tryton.
|
||||
# The COPYRIGHT file at the top level of this repository contains
|
||||
# the full copyright notices and license terms.
|
||||
|
||||
from .resultsimport import *
|
|
@ -1,427 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# This file is part of lims_instrument module for Tryton.
|
||||
# The COPYRIGHT file at the top level of this repository contains
|
||||
# the full copyright notices and license terms.
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
import xlrd
|
||||
from xlutils.copy import copy
|
||||
from datetime import datetime
|
||||
|
||||
from trytond.model import ModelView, fields
|
||||
from trytond.wizard import Wizard, StateView, StateTransition, Button
|
||||
from trytond.pool import Pool
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
__all__ = ['LimsNotebookLoadResultsFileStart',
|
||||
'LimsNotebookLoadResultsFileStartLine', 'LimsNotebookLoadResultsFileEmpty',
|
||||
'LimsNotebookLoadResultsFileResult', 'LimsNotebookLoadResultsFileWarning',
|
||||
'LimsNotebookLoadResultsFileExport', 'LimsNotebookLoadResultsFile']
|
||||
|
||||
|
||||
class LimsNotebookLoadResultsFileStart(ModelView):
|
||||
'Load Results from File'
|
||||
__name__ = 'lims.notebook.load_results_file.start'
|
||||
|
||||
results_importer = fields.Many2One('lims.resultsimport',
|
||||
'Results importer', required=True)
|
||||
lines = fields.One2Many('lims.notebook.load_results_file.start.line',
|
||||
None, 'Files', required=True)
|
||||
|
||||
|
||||
class LimsNotebookLoadResultsFileStartLine(ModelView):
|
||||
'Load Results from File'
|
||||
__name__ = 'lims.notebook.load_results_file.start.line'
|
||||
|
||||
infile = fields.Binary('File', required=True, filename='name')
|
||||
name = fields.Char('Name', readonly=True)
|
||||
|
||||
|
||||
class LimsNotebookLoadResultsFileEmpty(ModelView):
|
||||
'Load Results from File Empty'
|
||||
__name__ = 'lims.notebook.load_results_file.empty'
|
||||
|
||||
|
||||
class LimsNotebookLoadResultsFileResult(ModelView):
|
||||
'Process Results from File'
|
||||
__name__ = 'lims.notebook.load_results_file.result'
|
||||
|
||||
result_lines = fields.One2Many('lims.notebook.line', None, 'Lines',
|
||||
readonly=True)
|
||||
|
||||
|
||||
class LimsNotebookLoadResultsFileWarning(ModelView):
|
||||
'Load Results from File Warning'
|
||||
__name__ = 'lims.notebook.load_results_file.warning'
|
||||
|
||||
msg = fields.Text('Message')
|
||||
|
||||
|
||||
class LimsNotebookLoadResultsFileExport(ModelView):
|
||||
"Export Results from File"
|
||||
__name__ = 'lims.notebook.load_results_file.export'
|
||||
|
||||
file = fields.Binary('File', readonly=True)
|
||||
|
||||
|
||||
class LimsNotebookLoadResultsFile(Wizard):
|
||||
'Load Results from File'
|
||||
__name__ = 'lims.notebook.load_results_file'
|
||||
|
||||
start = StateView('lims.notebook.load_results_file.start',
|
||||
'lims_instrument.lims_load_results_file_start_view_form', [
|
||||
Button('Cancel', 'end', 'tryton-cancel'),
|
||||
Button('Collect', 'collect', 'tryton-go-next', default=True),
|
||||
])
|
||||
collect = StateTransition()
|
||||
empty = StateView('lims.notebook.load_results_file.empty',
|
||||
'lims_instrument.lims_load_results_file_empty_view_form', [
|
||||
Button('Try again', 'start', 'tryton-go-next'),
|
||||
Button('Close', 'end', 'tryton-close', default=True),
|
||||
])
|
||||
result = StateView('lims.notebook.load_results_file.result',
|
||||
'lims_instrument.lims_load_results_file_result_view_form', [
|
||||
Button('Cancel', 'cancel', 'tryton-cancel'),
|
||||
Button('Confirm', 'confirm', 'tryton-ok', default=True),
|
||||
])
|
||||
confirm = StateTransition()
|
||||
cancel = StateTransition()
|
||||
warning = StateView('lims.notebook.load_results_file.warning',
|
||||
'lims_instrument.lims_load_results_file_warning_view_form', [
|
||||
Button('Ok', 'close', 'tryton-ok'),
|
||||
])
|
||||
close = StateTransition()
|
||||
export = StateView('lims.notebook.load_results_file.export',
|
||||
'lims_instrument.lims_load_results_file_export_view_form', [
|
||||
Button('Done', 'end', 'tryton-close', default=True),
|
||||
])
|
||||
|
||||
def transition_collect(self):
|
||||
cursor = Transaction().connection.cursor()
|
||||
pool = Pool()
|
||||
LimsFraction = pool.get('lims.fraction')
|
||||
LimsNotebook = pool.get('lims.notebook')
|
||||
LimsNotebookLine = pool.get('lims.notebook.line')
|
||||
LimsAnalysis = pool.get('lims.analysis')
|
||||
|
||||
lines = []
|
||||
for fline in self.start.lines:
|
||||
self.start.results_importer.rawresults = {}
|
||||
self.start.results_importer.parse(fline.infile)
|
||||
raw_results = self.start.results_importer.rawresults
|
||||
fractions_numbers = list(raw_results.keys())
|
||||
if not fractions_numbers:
|
||||
continue
|
||||
|
||||
numbers = '\', \''.join(str(n) for n in fractions_numbers)
|
||||
cursor.execute('SELECT id, number '
|
||||
'FROM "' + LimsFraction._table + '" '
|
||||
'WHERE number IN (\'' + numbers + '\') '
|
||||
'ORDER BY number ASC')
|
||||
|
||||
for f in cursor.fetchall():
|
||||
cursor.execute('SELECT id '
|
||||
'FROM "' + LimsNotebook._table + '" '
|
||||
'WHERE fraction = %s '
|
||||
'LIMIT 1', (f[0],))
|
||||
notebook = cursor.fetchone()
|
||||
if not notebook:
|
||||
continue
|
||||
|
||||
for analysis in raw_results[f[1]].keys():
|
||||
cursor.execute('SELECT id '
|
||||
'FROM "' + LimsAnalysis._table + '" '
|
||||
'WHERE code = %s '
|
||||
'AND automatic_acquisition = TRUE '
|
||||
'LIMIT 1', (analysis,))
|
||||
if not cursor.fetchone():
|
||||
continue
|
||||
|
||||
for rep in raw_results[f[1]][analysis].keys():
|
||||
clause = [
|
||||
('notebook', '=', notebook[0]),
|
||||
('analysis', '=', analysis),
|
||||
('repetition', '=', rep),
|
||||
('result', 'in', [None, '']),
|
||||
('converted_result', 'in', [None, '']),
|
||||
('literal_result', 'in', [None, '']),
|
||||
('result_modifier', 'not in', ['nd', 'pos', 'neg',
|
||||
'ni', 'abs', 'pre', 'na']),
|
||||
('converted_result_modifier', 'not in',
|
||||
['nd', 'pos', 'neg', 'ni', 'abs', 'pre']),
|
||||
]
|
||||
line = LimsNotebookLine.search(clause)
|
||||
if line:
|
||||
data = raw_results[f[1]][analysis][rep]
|
||||
res = self.get_results(line[0], data)
|
||||
if res:
|
||||
LimsNotebookLine.write([line[0]], res)
|
||||
lines.append(line[0])
|
||||
|
||||
if lines:
|
||||
self.result.result_lines = [l.id for l in lines]
|
||||
return 'result'
|
||||
return 'empty'
|
||||
|
||||
def get_results(self, line, data):
|
||||
pool = Pool()
|
||||
LimsDevice = pool.get('lims.lab.device')
|
||||
|
||||
res = {}
|
||||
if 'result' in data or 'literal_result' in data:
|
||||
if 'result' in data:
|
||||
res['imported_result'] = unicode(float(data['result']))
|
||||
if 'literal_result' in data:
|
||||
res['imported_literal_result'] = data['literal_result']
|
||||
res['imported_end_date'] = (data['end_date'] if 'end_date' in data
|
||||
else line.end_date)
|
||||
if 'professionals' in data:
|
||||
res['imported_professionals'] = data['professionals']
|
||||
if 'chromatogram' in data:
|
||||
res['imported_chromatogram'] = data['chromatogram']
|
||||
device = data['device'] if 'device' in data else None
|
||||
if device:
|
||||
dev = LimsDevice.search([('code', '=', device)])
|
||||
if dev:
|
||||
res['imported_device'] = dev[0].id
|
||||
if 'dilution_factor' in data:
|
||||
res['imported_dilution_factor'] = data['dilution_factor']
|
||||
if 'rm_correction_formula' in data:
|
||||
res['imported_rm_correction_formula'] = (
|
||||
data['rm_correction_formula'])
|
||||
return res
|
||||
|
||||
def default_result(self, fields):
|
||||
default = {}
|
||||
default['result_lines'] = [l.id for l in self.result.result_lines]
|
||||
return default
|
||||
|
||||
def get_professionals(self, professionals_codes):
|
||||
'''
|
||||
This function gets a string with one or more professionals codes,
|
||||
separated by commas, like: 'ABC' or 'JLB, ABC'
|
||||
It returns the professionals
|
||||
'''
|
||||
cursor = Transaction().connection.cursor()
|
||||
pool = Pool()
|
||||
Professional = pool.get('lims.laboratory.professional')
|
||||
|
||||
res = []
|
||||
professionals = ''.join(professionals_codes.split())
|
||||
professionals = professionals.split(',')
|
||||
for professional in professionals:
|
||||
cursor.execute('SELECT id, code '
|
||||
'FROM "' + Professional._table + '" '
|
||||
'WHERE code = %s '
|
||||
'LIMIT 1', (professional,))
|
||||
prof = cursor.fetchone()
|
||||
if prof:
|
||||
res.append(prof)
|
||||
return res
|
||||
|
||||
def check_professionals(self, professionals, method):
|
||||
cursor = Transaction().connection.cursor()
|
||||
pool = Pool()
|
||||
LabProfessionalMethod = pool.get('lims.lab.professional.method')
|
||||
|
||||
validated = False
|
||||
msg = ''
|
||||
for professional in professionals:
|
||||
cursor.execute('SELECT state '
|
||||
'FROM "' + LabProfessionalMethod._table + '" '
|
||||
'WHERE professional = %s '
|
||||
'AND method = %s '
|
||||
'AND type = \'analytical\' '
|
||||
'LIMIT 1', (professional[0], method.id))
|
||||
qualification = cursor.fetchone()
|
||||
if not qualification:
|
||||
validated = False
|
||||
msg += '%s not qualified for method: %s' % (
|
||||
professional[1], method.code)
|
||||
return validated, msg
|
||||
elif qualification[0] == 'training':
|
||||
if not validated:
|
||||
msg += '%s in training for method: %s. ' \
|
||||
'Add qualified professional' % (
|
||||
professional[1], method.code)
|
||||
elif (qualification[0] in ('qualified', 'requalified')):
|
||||
validated = True
|
||||
|
||||
return validated, msg
|
||||
|
||||
def transition_confirm(self):
|
||||
pool = Pool()
|
||||
LimsNotebookLine = pool.get('lims.notebook.line')
|
||||
|
||||
NOW = datetime.now()
|
||||
warnings = False
|
||||
messages = ''
|
||||
# Write Results to Notebook lines
|
||||
for line in self.result.result_lines:
|
||||
notebook_line_write = {
|
||||
'imported_result': None,
|
||||
'imported_literal_result': None,
|
||||
'imported_end_date': None,
|
||||
'imported_professionals': None,
|
||||
'imported_chromatogram': None,
|
||||
'imported_device': None,
|
||||
'imported_dilution_factor': None,
|
||||
'imported_rm_correction_formula': None,
|
||||
}
|
||||
|
||||
prevent_line = False
|
||||
outcome = ''
|
||||
if line.result != line.imported_result:
|
||||
if line.imported_result != '-1000.0':
|
||||
notebook_line_write['result'] = line.imported_result
|
||||
else:
|
||||
notebook_line_write['result'] = None
|
||||
notebook_line_write['result_modifier'] = 'na'
|
||||
notebook_line_write['report'] = False
|
||||
notebook_line_write['annulled'] = True
|
||||
notebook_line_write['annulment_date'] = NOW
|
||||
if line.literal_result != line.imported_literal_result:
|
||||
notebook_line_write['literal_result'] = (
|
||||
line.imported_literal_result)
|
||||
if line.end_date != line.imported_end_date:
|
||||
if line.imported_result != '-1000.0':
|
||||
if (line.start_date and
|
||||
line.start_date <= line.imported_end_date):
|
||||
notebook_line_write['end_date'] = (
|
||||
line.imported_end_date)
|
||||
else:
|
||||
prevent_line = True
|
||||
outcome = 'End date cannot be lower than Start date'
|
||||
else:
|
||||
notebook_line_write['end_date'] = None
|
||||
if line.chromatogram != line.imported_chromatogram:
|
||||
notebook_line_write['chromatogram'] = (
|
||||
line.imported_chromatogram)
|
||||
if line.device != line.imported_device:
|
||||
notebook_line_write['device'] = line.imported_device
|
||||
if line.dilution_factor != line.imported_dilution_factor:
|
||||
notebook_line_write['dilution_factor'] = (
|
||||
line.imported_dilution_factor)
|
||||
if (line.rm_correction_formula !=
|
||||
line.imported_rm_correction_formula):
|
||||
notebook_line_write['rm_correction_formula'] = (
|
||||
line.imported_rm_correction_formula)
|
||||
|
||||
if line.imported_professionals:
|
||||
profs = self.get_professionals(line.imported_professionals)
|
||||
if profs:
|
||||
validated, msg = self.check_professionals(
|
||||
profs, line.method)
|
||||
if validated:
|
||||
professionals = [{'professional': p[0]}
|
||||
for p in profs]
|
||||
notebook_line_write['professionals'] = (
|
||||
[('delete', [p.id for p in line.professionals])]
|
||||
+ [('create', professionals)])
|
||||
else:
|
||||
prevent_line = True
|
||||
outcome = msg
|
||||
else:
|
||||
prevent_line = True
|
||||
outcome = ('Professional(s) with code '
|
||||
+ unicode(line.imported_professionals)
|
||||
+ ' not identified')
|
||||
|
||||
if not prevent_line:
|
||||
try:
|
||||
LimsNotebookLine.write([line], notebook_line_write)
|
||||
except Exception as e:
|
||||
prevent_line = True
|
||||
outcome = unicode(e)
|
||||
original_profs = [{'professional': p.professional}
|
||||
for p in line.professionals]
|
||||
notebook_line_original_values = {
|
||||
'result': line.result,
|
||||
'literal_result': line.literal_result,
|
||||
'end_date': line.end_date,
|
||||
'professionals': (
|
||||
[('delete', [p.id for p in line.professionals])]
|
||||
+ [('create', original_profs,)]),
|
||||
'chromatogram': line.chromatogram,
|
||||
'device': line.device,
|
||||
'dilution_factor': line.dilution_factor,
|
||||
'rm_correction_formula': line.rm_correction_formula,
|
||||
}
|
||||
LimsNotebookLine.write(
|
||||
[line], notebook_line_original_values)
|
||||
else:
|
||||
outcome = 'OK'
|
||||
|
||||
# Update rawresults
|
||||
row_num = 0
|
||||
if self.start.results_importer.exportResults() or prevent_line:
|
||||
rawresults = self.start.results_importer.rawresults
|
||||
number = line.fraction.number
|
||||
if number in rawresults:
|
||||
code = line.analysis.code
|
||||
if code in rawresults[number]:
|
||||
rep = line.repetition
|
||||
if rep in rawresults[number][code]:
|
||||
rawresults[number][code][rep]['outcome'] = outcome
|
||||
row_num = rawresults[number][code][rep][
|
||||
'row_number']
|
||||
|
||||
if prevent_line:
|
||||
warnings = True
|
||||
messages += str(row_num) + ': ' + outcome + '\n'
|
||||
|
||||
if warnings:
|
||||
self.warning.msg = messages
|
||||
return 'warning'
|
||||
else:
|
||||
if self.start.results_importer.exportResults():
|
||||
return 'end' # 'export'
|
||||
return 'end'
|
||||
|
||||
def transition_cancel(self):
|
||||
LimsNotebookLine = Pool().get('lims.notebook.line')
|
||||
# Clean results froms Notebook lines
|
||||
notebook_line_clean = {
|
||||
'imported_result': None,
|
||||
'imported_literal_result': None,
|
||||
'imported_end_date': None,
|
||||
'imported_professionals': None,
|
||||
'imported_chromatogram': None,
|
||||
'imported_device': None,
|
||||
'imported_dilution_factor': None,
|
||||
'imported_rm_correction_formula': None,
|
||||
}
|
||||
LimsNotebookLine.write(
|
||||
list(self.result.result_lines), notebook_line_clean)
|
||||
return 'end'
|
||||
|
||||
def default_warning(self, fields):
|
||||
defaults = {}
|
||||
if self.warning.msg:
|
||||
defaults['msg'] = self.warning.msg
|
||||
return defaults
|
||||
|
||||
def transition_close(self):
|
||||
if self.start.results_importer.exportResults():
|
||||
return 'end' # 'export'
|
||||
return 'end'
|
||||
|
||||
def default_export(self, fields):
|
||||
rawresults = self.start.results_importer.rawresults
|
||||
filedata = StringIO.StringIO(self.start.infile) # TODO: refactoring
|
||||
workbook = xlrd.open_workbook(file_contents=filedata.getvalue(),
|
||||
formatting_info=True)
|
||||
wb_copy = copy(workbook)
|
||||
for fraction in rawresults:
|
||||
for analysis in rawresults[fraction]:
|
||||
for rep in rawresults[fraction][analysis]:
|
||||
repetition = rawresults[fraction][analysis][rep]
|
||||
if 'outcome' in repetition and 'status_cell' in repetition:
|
||||
sheet, row, col = repetition['status_cell']
|
||||
wb_sheet = wb_copy.get_sheet(sheet)
|
||||
wb_sheet.write(row, col, repetition['outcome'])
|
||||
output = StringIO.StringIO()
|
||||
wb_copy.save(output)
|
||||
return {'file': bytearray(output.getvalue())}
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2014-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2014-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2014-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .resultsimport import *
|
||||
from . import resultsimport
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
LimsResultsImport,
|
||||
resultsimport.ResultsImport,
|
||||
module='lims_instrument_custom_set', type_='model')
|
||||
|
|
|
@ -23,7 +23,7 @@ def getControllerName():
|
|||
|
||||
|
||||
def parse(self, infile):
|
||||
LimsLabWorkYear = Pool().get('lims.lab.workyear')
|
||||
LabWorkYear = Pool().get('lims.lab.workyear')
|
||||
|
||||
filedata = StringIO.StringIO(infile)
|
||||
workbook = xlrd.open_workbook(file_contents=filedata.getvalue())
|
||||
|
@ -69,7 +69,7 @@ def parse(self, infile):
|
|||
header_found = False
|
||||
continue
|
||||
|
||||
workyear = LimsLabWorkYear.search(
|
||||
workyear = LabWorkYear.search(
|
||||
['code', '=', str(int(row[1]))
|
||||
])
|
||||
padding = None
|
||||
|
|
Binary file not shown.
|
@ -1,82 +0,0 @@
|
|||
Módulo Lims Instrument Custom Set
|
||||
#################################
|
||||
|
||||
Este módulo define dos importadores de resultados:
|
||||
-Planilla personalizada - CSV (no implementada aún)
|
||||
-Planilla personalizada - XLS
|
||||
|
||||
Se trata en ambos casos de planillas definidas por el usuario, sin relación
|
||||
con archivos exportados por un instrumento particular.
|
||||
|
||||
|
||||
Planilla personalizada - XLS
|
||||
****************************
|
||||
|
||||
Este importador es capaz de interpretar una planilla de Excel a partir de
|
||||
ciertos parámetros que puede definir el usuario, es decir que no responden al
|
||||
esquema de ningún instrumento o equipo.
|
||||
|
||||
Utiliza la librería 'xlrd' para extraer la información de las planillas Excel:
|
||||
http://www.python-excel.org/
|
||||
|
||||
Los parámetros que es necesario definir en cada hoja son:
|
||||
|
||||
- 'Analysis Code': indica el código del análisis al que corresponden los
|
||||
valores expuestos en la hoja. Si en una celda se pone 'Analysis Code', en la
|
||||
celda que esté a su derecha se buscará el código del análisis.
|
||||
|
||||
- 'Data Header': si se indica este valor en una celda, el importador buscará
|
||||
en la fila inmediata inferior la cabecera de los valores que se
|
||||
pretende ingresar.
|
||||
De esta cabecera, las cuatro primeras columnas deben corresponder a:
|
||||
- Muestra
|
||||
- Año
|
||||
- Fracción
|
||||
- Repetición
|
||||
|
||||
Sin importar cuáles sean los nombres definidos para esas columnas, los cuatro
|
||||
valores se harán corresponder, en ese orden, con esos datos, que son los que
|
||||
permiten identificar una línea de cuaderno.
|
||||
De ahí en más, las restantes columnas pueden corresponder a cualquier valor
|
||||
que determine el usuario, sin límites.
|
||||
Para los nombres de las columnas pueden utilizarse espacios y puntos, pero se
|
||||
recomienda evitar cualquier caracter que pueda confundirse con una fórmula o
|
||||
expresión algebráica, por ejemplo: / + - ( ) *
|
||||
También es preferible no utilizar caracteres no ASCII, ya que el parseador
|
||||
de fórmulas pueden rechazarlo por inválido e ignorarlo.
|
||||
|
||||
- 'Formula': a la derecha de aquella celda que contenga el valor 'Formula' se
|
||||
deberá definir la fórmula de cálculo.
|
||||
Para que la fórmula pueda ser correctamente mapeada, las variables deben
|
||||
coincidir con el nombre de alguna de las columnas cabecera definidas como
|
||||
'Data Header'.
|
||||
La cabecera puede contener columnas que no son utilizadas en la fórmula, pero
|
||||
para que la fórmula se aplique correctamente todas sus variables deben estar
|
||||
representadas en la cabecera.
|
||||
|
||||
Si al analizar la hoja no se pueden determinar estos tres parámetros (
|
||||
'Analysis Code', 'Data Header' y 'Formula'), el importador de datos concluirá
|
||||
la lectura sin tomar datos.
|
||||
|
||||
Hay un último valor, opcional, que tiene una función especial:
|
||||
- '###': si se pone ### en la primera celda (A1), la hoja es ignorada; puede
|
||||
ser útil si se desea que una hoja no sea tenida en cuenta durante la
|
||||
importación.
|
||||
|
||||
|
||||
Carga de datos
|
||||
**************
|
||||
Para empezar a cargar valores es necesario copiar la cabecera definida como
|
||||
'Data Header' y en las filas que siguen cargar los datos.
|
||||
Los datos deben ser númericos y deben existir (no pueden dejarse vacíos).
|
||||
|
||||
Si alguna fila se deja en blanco, el importador de datos continuará con las
|
||||
siguientes hasta volver a encontrar otra vez la cabecera, circunstancia en la
|
||||
cual continuará con la captación de valores.
|
||||
|
||||
Si ya no se encuentra la cabecera, la lectura seguirá sin captar valores,
|
||||
hasta llegar al final de la hoja. Una vez concluida una hoja se sigue con la
|
||||
siguiente.
|
||||
|
||||
En distintas hojas de la planilla de cálculo se puede hacer referencia a la
|
||||
misma fracción, quizá con un análisis distinto.
|
|
@ -7,10 +7,10 @@ from trytond.pool import PoolMeta
|
|||
import custom_set_csv
|
||||
import custom_set_xls
|
||||
|
||||
__all__ = ['LimsResultsImport']
|
||||
__all__ = ['ResultsImport']
|
||||
|
||||
|
||||
class LimsResultsImport:
|
||||
class ResultsImport:
|
||||
__name__ = 'lims.resultsimport'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -19,7 +19,7 @@ class LimsResultsImport:
|
|||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(LimsResultsImport, cls).__setup__()
|
||||
super(ResultsImport, cls).__setup__()
|
||||
controllers = [
|
||||
('custom_set_csv', 'Custom Set - CSV'),
|
||||
('custom_set_xls', 'Custom Set - XLS'),
|
||||
|
@ -34,7 +34,7 @@ class LimsResultsImport:
|
|||
elif self.name == 'custom_set_xls':
|
||||
self.controller = custom_set_xls
|
||||
else:
|
||||
return super(LimsResultsImport, self).loadController()
|
||||
return super(ResultsImport, self).loadController()
|
||||
|
||||
def getAnalysisCode(self, row):
|
||||
return self.controller.getAnalysisCode(self, row)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[tryton]
|
||||
version=4.4.0
|
||||
version=4.8.0
|
||||
depends:
|
||||
lims_instrument
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2014-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2014-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2014-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .resultsimport import *
|
||||
from . import resultsimport
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
LimsResultsImport,
|
||||
resultsimport.ResultsImport,
|
||||
module='lims_instrument_generic_form', type_='model')
|
||||
|
|
Binary file not shown.
|
@ -26,7 +26,7 @@ def getControllerName():
|
|||
|
||||
|
||||
def parse(self, infile):
|
||||
LimsLabWorkYear = Pool().get('lims.lab.workyear')
|
||||
LabWorkYear = Pool().get('lims.lab.workyear')
|
||||
|
||||
filedata = StringIO.StringIO(infile)
|
||||
workbook = xlrd.open_workbook(file_contents=filedata.getvalue())
|
||||
|
@ -59,7 +59,7 @@ def parse(self, infile):
|
|||
row[COL['E']].ctype == xlrd.XL_CELL_NUMBER) else None
|
||||
year = int(row[COL['F']].value) if (
|
||||
row[COL['F']].ctype == xlrd.XL_CELL_NUMBER) else None
|
||||
workyear = LimsLabWorkYear.search(
|
||||
workyear = LabWorkYear.search(
|
||||
['code', '=', str(year)])
|
||||
padding = None
|
||||
if workyear and workyear[0] and workyear[0].sample_sequence:
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
from trytond.pool import PoolMeta
|
||||
import generic_form_xls
|
||||
|
||||
__all__ = ['LimsResultsImport']
|
||||
__all__ = ['ResultsImport']
|
||||
|
||||
|
||||
class LimsResultsImport:
|
||||
class ResultsImport:
|
||||
__name__ = 'lims.resultsimport'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(LimsResultsImport, cls).__setup__()
|
||||
super(ResultsImport, cls).__setup__()
|
||||
controllers = [
|
||||
('generic_form_xls', 'Generic Form - XLS'),
|
||||
]
|
||||
|
@ -27,4 +27,4 @@ class LimsResultsImport:
|
|||
if self.name == 'generic_form_xls':
|
||||
self.controller = generic_form_xls
|
||||
else:
|
||||
return super(LimsResultsImport, self).loadController()
|
||||
return super(ResultsImport, self).loadController()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[tryton]
|
||||
version=4.4.0
|
||||
version=4.8.0
|
||||
depends:
|
||||
lims_instrument
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2014-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2014-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2014-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .resultsimport import *
|
||||
from . import resultsimport
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
LimsResultsImport,
|
||||
resultsimport.ResultsImport,
|
||||
module='lims_instrument_generic_service', type_='model')
|
||||
|
|
|
@ -25,7 +25,7 @@ def getControllerName():
|
|||
|
||||
|
||||
def parse(self, infile):
|
||||
LimsLabWorkYear = Pool().get('lims.lab.workyear')
|
||||
LabWorkYear = Pool().get('lims.lab.workyear')
|
||||
|
||||
filedata = StringIO.StringIO(infile)
|
||||
workbook = xlrd.open_workbook(file_contents=filedata.getvalue())
|
||||
|
@ -58,7 +58,7 @@ def parse(self, infile):
|
|||
row4th[COL['E']].ctype == xlrd.XL_CELL_NUMBER) else None
|
||||
year = int(row4th[COL['F']].value) if (
|
||||
row4th[COL['F']].ctype == xlrd.XL_CELL_NUMBER) else None
|
||||
workyear = LimsLabWorkYear.search(
|
||||
workyear = LabWorkYear.search(
|
||||
['code', '=', str(year)])
|
||||
padding = None
|
||||
if workyear and workyear[0] and workyear[0].sample_sequence:
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
from trytond.pool import PoolMeta
|
||||
import generic_service_xls
|
||||
|
||||
__all__ = ['LimsResultsImport']
|
||||
__all__ = ['ResultsImport']
|
||||
|
||||
|
||||
class LimsResultsImport:
|
||||
class ResultsImport:
|
||||
__name__ = 'lims.resultsimport'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(LimsResultsImport, cls).__setup__()
|
||||
super(ResultsImport, cls).__setup__()
|
||||
controllers = [
|
||||
('generic_service_xls', 'Generic Service Form - XLS'),
|
||||
]
|
||||
|
@ -27,4 +27,4 @@ class LimsResultsImport:
|
|||
if self.name == 'generic_service_xls':
|
||||
self.controller = generic_service_xls
|
||||
else:
|
||||
return super(LimsResultsImport, self).loadController()
|
||||
return super(ResultsImport, self).loadController()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[tryton]
|
||||
version=4.4.0
|
||||
version=4.8.0
|
||||
depends:
|
||||
lims_instrument
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2013-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -3,34 +3,32 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .stock import *
|
||||
from .configuration import *
|
||||
from .production import *
|
||||
from report import *
|
||||
from . import stock
|
||||
from . import configuration
|
||||
from . import production
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
PurityDegree,
|
||||
Brand,
|
||||
FamilyEquivalent,
|
||||
LotCategory,
|
||||
Lot,
|
||||
Move,
|
||||
ShipmentIn,
|
||||
Template,
|
||||
Product,
|
||||
ProductionConfiguration,
|
||||
ProductionConfigurationLotSequence,
|
||||
LimsConfiguration,
|
||||
LimsConfigurationSolvents,
|
||||
BOM,
|
||||
Production,
|
||||
stock.PurityDegree,
|
||||
stock.Brand,
|
||||
stock.FamilyEquivalent,
|
||||
stock.LotCategory,
|
||||
stock.Lot,
|
||||
stock.Move,
|
||||
stock.ShipmentIn,
|
||||
stock.Template,
|
||||
stock.Product,
|
||||
configuration.ProductionConfiguration,
|
||||
configuration.ProductionConfigurationLotSequence,
|
||||
configuration.Configuration,
|
||||
configuration.ConfigurationSolvents,
|
||||
production.BOM,
|
||||
production.Production,
|
||||
module='lims_production', type_='model')
|
||||
Pool.register(
|
||||
UpdateCostPrice,
|
||||
LimsMoveProductionRelated,
|
||||
stock.MoveProductionRelated,
|
||||
module='lims_production', type_='wizard')
|
||||
Pool.register(
|
||||
FamilyEquivalentReport,
|
||||
production.FamilyEquivalentReport,
|
||||
module='lims_production', type_='report')
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains
|
||||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond import backend
|
||||
from trytond.model import ModelSQL, fields
|
||||
from trytond.pool import PoolMeta, Pool
|
||||
from trytond.pyson import Eval
|
||||
from trytond.tools.multivalue import migrate_property
|
||||
from trytond.modules.company.model import CompanyValueMixin
|
||||
|
||||
__all__ = ['ProductionConfiguration', 'ProductionConfigurationLotSequence',
|
||||
'LimsConfiguration', 'LimsConfigurationSolvents']
|
||||
'Configuration', 'ConfigurationSolvents']
|
||||
|
||||
|
||||
class ProductionConfiguration:
|
||||
|
@ -59,7 +57,7 @@ class ProductionConfigurationLotSequence(ModelSQL, CompanyValueMixin):
|
|||
return None
|
||||
|
||||
|
||||
class LimsConfiguration:
|
||||
class Configuration:
|
||||
__name__ = 'lims.configuration'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -94,7 +92,7 @@ class LimsConfiguration:
|
|||
return res
|
||||
|
||||
|
||||
class LimsConfigurationSolvents(ModelSQL):
|
||||
class ConfigurationSolvents(ModelSQL):
|
||||
'Configuration - Solvents'
|
||||
__name__ = 'lims.configuration.solvents'
|
||||
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<tryton>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Sequences for Lot -->
|
||||
|
||||
<record model="ir.sequence.type" id="seq_type_lot">
|
||||
<field name="name">Lot</field>
|
||||
<field name="code">stock.lot</field>
|
||||
</record>
|
||||
<record model="ir.sequence.type-res.group"
|
||||
id="seq_type_lot_group_admin">
|
||||
<field name="sequence_type" ref="seq_type_lot"/>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
</record>
|
||||
<record model="ir.sequence" id="seq_lot">
|
||||
<field name="name">Lot</field>
|
||||
<field name="code">stock.lot</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<!-- Configuration / Material -->
|
||||
<menuitem name="Material" parent="lims.lims_config"
|
||||
id="lims_config_material" sequence="50"/>
|
||||
<menuitem parent="lims_config_material" action="act_lims_brand_list"
|
||||
id="lims_brand_menu" sequence="10"/>
|
||||
<menuitem parent="lims_config_material" action="act_lims_purity_degree_list"
|
||||
id="lims_purity_degree_menu" sequence="20"/>
|
||||
<menuitem parent="lims_config_material" action="act_lims_family_equivalent_list"
|
||||
id="lims_family_equivalent_menu" sequence="30"/>
|
||||
|
||||
<!-- Other menu items -->
|
||||
|
||||
<menuitem parent="stock.menu_configuration" action="act_lims_lot_category_list"
|
||||
id="lims_lot_category_menu" sequence="10"/>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,20 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Family/Equivalents Report -->
|
||||
|
||||
<record model="ir.action.report" id="report_family_equivalent">
|
||||
<field name="name">Family/Equivalents</field>
|
||||
<field name="report_name">lims.family.equivalent.report</field>
|
||||
<field name="report">lims_production/report/family_equivalent.odt</field>
|
||||
<field name="extension">pdf</field>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="report_family_equivalent_keyword">
|
||||
<field name="keyword">form_print</field>
|
||||
<field name="model">lims.family.equivalent,-1</field>
|
||||
<field name="action" ref="report_family_equivalent"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -7,8 +7,10 @@ from decimal import Decimal
|
|||
from trytond.model import fields
|
||||
from trytond.pyson import Eval, Bool
|
||||
from trytond.pool import PoolMeta, Pool
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.report import Report
|
||||
|
||||
__all__ = ['BOM', 'Production']
|
||||
__all__ = ['BOM', 'Production', 'FamilyEquivalentReport']
|
||||
|
||||
|
||||
class BOM:
|
||||
|
@ -229,3 +231,45 @@ class Production:
|
|||
from_location = product_location
|
||||
return super(Production, self)._explode_move_values(from_location,
|
||||
to_location, company, bom_io, quantity)
|
||||
|
||||
|
||||
class FamilyEquivalentReport(Report):
|
||||
'Family/Equivalent'
|
||||
__name__ = 'lims.family.equivalent.report'
|
||||
|
||||
@classmethod
|
||||
def get_context(cls, records, data):
|
||||
pool = Pool()
|
||||
Company = pool.get('company.company')
|
||||
|
||||
report_context = super(FamilyEquivalentReport, cls).get_context(
|
||||
records, data)
|
||||
|
||||
report_context['company'] = Company(Transaction().context['company'])
|
||||
report_context['records'] = cls._get_family_records(records)
|
||||
report_context['compute_qty'] = cls.compute_qty
|
||||
return report_context
|
||||
|
||||
@classmethod
|
||||
def _get_family_records(cls, records):
|
||||
pool = Pool()
|
||||
Location = pool.get('stock.location')
|
||||
Date_ = pool.get('ir.date')
|
||||
FamilyEquivalent = pool.get('lims.family.equivalent')
|
||||
|
||||
locations = Location.search([
|
||||
('type', '=', 'storage'),
|
||||
])
|
||||
context = {}
|
||||
context['locations'] = [l.id for l in locations]
|
||||
context['stock_date_end'] = Date_.today()
|
||||
|
||||
with Transaction().set_context(context):
|
||||
res = FamilyEquivalent.browse(records)
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def compute_qty(cls, from_uom, qty, to_uom):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
return Uom.compute_qty(from_uom, qty, to_uom)
|
||||
|
|
|
@ -1,9 +1,144 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Sequences for Lot -->
|
||||
|
||||
<record model="ir.sequence.type" id="seq_type_lot">
|
||||
<field name="name">Lot</field>
|
||||
<field name="code">stock.lot</field>
|
||||
</record>
|
||||
<record model="ir.sequence.type-res.group"
|
||||
id="seq_type_lot_group_admin">
|
||||
<field name="sequence_type" ref="seq_type_lot"/>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
</record>
|
||||
<record model="ir.sequence" id="seq_lot">
|
||||
<field name="name">Lot</field>
|
||||
<field name="code">stock.lot</field>
|
||||
</record>
|
||||
|
||||
<!-- Groups -->
|
||||
|
||||
<record model="res.group" id="group_lims_conf_material_readonly">
|
||||
<field name="name">Lims Configuration Material Read Only</field>
|
||||
</record>
|
||||
<record model="res.group" id="group_lims_conf_material_admin">
|
||||
<field name="name">Lims Configuration Material Admin</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lims_conf_material_admin">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_conf_material_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="res.group" id="group_lims_lot_input_prod">
|
||||
<field name="name">Lims Lot Input for production</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lot_input_prod">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_lot_input_prod"/>
|
||||
</record>
|
||||
|
||||
<record model="res.group" id="group_lims_lot_prod_sale">
|
||||
<field name="name">Lims Lot Production for sale</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lot_prod_sale">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_lot_prod_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="res.group" id="group_lims_lot_domestic_use">
|
||||
<field name="name">Lims Lot Production for domestic use</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lot_domestic_use">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_lot_domestic_use"/>
|
||||
</record>
|
||||
|
||||
<!-- Production -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_production_view_form">
|
||||
<field name="model">production</field>
|
||||
<field name="inherit" ref="production.production_view_form"/>
|
||||
<field name="name">production_production_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_production_view_list">
|
||||
<field name="model">production</field>
|
||||
<field name="inherit" ref="production.production_view_list"/>
|
||||
<field name="name">production_production_list</field>
|
||||
</record>
|
||||
|
||||
<!-- BOM -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_bom_view_form">
|
||||
<field name="model">production.bom</field>
|
||||
<field name="inherit" ref="production.bom_view_form"/>
|
||||
<field name="name">production_bom_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_bom_view_list">
|
||||
<field name="model">production.bom</field>
|
||||
<field name="inherit" ref="production.bom_view_list"/>
|
||||
<field name="name">production_bom_list</field>
|
||||
</record>
|
||||
|
||||
<!-- Move actions related -->
|
||||
|
||||
<record model="ir.action.act_window" id="act_production_related">
|
||||
<field name="name">Related Productions</field>
|
||||
<field name="res_model">production</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_production_related_list_view">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="production.production_view_list"/>
|
||||
<field name="act_window" ref="act_production_related"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_production_related_form_view">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="production.production_view_form"/>
|
||||
<field name="act_window" ref="act_production_related"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.wizard" id="wizard_move_production_related">
|
||||
<field name="name">Related Productions</field>
|
||||
<field name="wiz_name">lims.move.production_related</field>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="act_open_production_keyword">
|
||||
<field name="keyword">form_relate</field>
|
||||
<field name="model">stock.move,-1</field>
|
||||
<field name="action" ref="wizard_move_production_related"/>
|
||||
</record>
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<!-- Configuration / Material -->
|
||||
<menuitem name="Material" parent="lims.lims_config"
|
||||
id="lims_config_material" sequence="50"/>
|
||||
<menuitem parent="lims_config_material" action="act_lims_brand_list"
|
||||
id="lims_brand_menu" sequence="10"/>
|
||||
<menuitem parent="lims_config_material" action="act_lims_purity_degree_list"
|
||||
id="lims_purity_degree_menu" sequence="20"/>
|
||||
<menuitem parent="lims_config_material" action="act_lims_family_equivalent_list"
|
||||
id="lims_family_equivalent_menu" sequence="30"/>
|
||||
|
||||
<!-- Other menu items -->
|
||||
|
||||
<menuitem parent="stock.menu_configuration" action="act_lims_lot_category_list"
|
||||
id="lims_lot_category_menu" sequence="10"/>
|
||||
|
||||
<!-- Family/Equivalents Report -->
|
||||
|
||||
<record model="ir.action.report" id="report_family_equivalent">
|
||||
<field name="name">Family/Equivalents</field>
|
||||
<field name="report_name">lims.family.equivalent.report</field>
|
||||
<field name="report">lims_production/report/family_equivalent.odt</field>
|
||||
<field name="extension">pdf</field>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="report_family_equivalent_keyword">
|
||||
<field name="keyword">form_print</field>
|
||||
<field name="model">lims.family.equivalent,-1</field>
|
||||
<field name="action" ref="report_family_equivalent"/>
|
||||
</record>
|
||||
|
||||
<!-- Access Rights on Models -->
|
||||
|
||||
<record model="ir.model.access" id="access_brand">
|
||||
|
@ -220,12 +355,12 @@ this repository contains the full copyright notices and license terms. -->
|
|||
|
||||
<!-- Configuration / Material -->
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_group_conf_material_readonly">
|
||||
<field name="menu" ref="lims.lims_menu"/>
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_laboratory_group_conf_material_readonly">
|
||||
<field name="menu" ref="lims.lims_laboratory"/>
|
||||
<field name="group" ref="group_lims_conf_material_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_group_conf_material_admin">
|
||||
<field name="menu" ref="lims.lims_menu"/>
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_laboratory_group_conf_material_admin">
|
||||
<field name="menu" ref="lims.lims_laboratory"/>
|
||||
<field name="group" ref="group_lims_conf_material_admin"/>
|
||||
</record>
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Production -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_production_view_form">
|
||||
<field name="model">production</field>
|
||||
<field name="inherit" ref="production.production_view_form"/>
|
||||
<field name="name">production_production_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_production_view_list">
|
||||
<field name="model">production</field>
|
||||
<field name="inherit" ref="production.production_view_list"/>
|
||||
<field name="name">production_production_list</field>
|
||||
</record>
|
||||
|
||||
<!-- BOM -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_bom_view_form">
|
||||
<field name="model">production.bom</field>
|
||||
<field name="inherit" ref="production.bom_view_form"/>
|
||||
<field name="name">production_bom_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_bom_view_list">
|
||||
<field name="model">production.bom</field>
|
||||
<field name="inherit" ref="production.bom_view_list"/>
|
||||
<field name="name">production_bom_list</field>
|
||||
</record>
|
||||
|
||||
<!-- Move actions related -->
|
||||
|
||||
<record model="ir.action.act_window" id="act_production_related">
|
||||
<field name="name">Related Productions</field>
|
||||
<field name="res_model">production</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_production_related_list_view">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="production.production_view_list"/>
|
||||
<field name="act_window" ref="act_production_related"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_production_related_form_view">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="production.production_view_form"/>
|
||||
<field name="act_window" ref="act_production_related"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.wizard" id="wizard_move_production_related">
|
||||
<field name="name">Related Productions</field>
|
||||
<field name="wiz_name">lims.move.production_related</field>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="act_open_production_keyword">
|
||||
<field name="keyword">form_relate</field>
|
||||
<field name="model">stock.move,-1</field>
|
||||
<field name="action" ref="wizard_move_production_related"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,5 +0,0 @@
|
|||
# This file is part of lims_production module for Tryton.
|
||||
# The COPYRIGHT file at the top level of this repository contains
|
||||
# the full copyright notices and license terms.
|
||||
|
||||
from .lims_report import *
|
|
@ -1,52 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# This file is part of lims_production module for Tryton.
|
||||
# The COPYRIGHT file at the top level of this repository contains
|
||||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.report import Report
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pool import Pool
|
||||
|
||||
__all__ = ['FamilyEquivalentReport']
|
||||
|
||||
|
||||
class FamilyEquivalentReport(Report):
|
||||
'Family/Equivalent'
|
||||
__name__ = 'lims.family.equivalent.report'
|
||||
|
||||
@classmethod
|
||||
def get_context(cls, records, data):
|
||||
pool = Pool()
|
||||
Company = pool.get('company.company')
|
||||
|
||||
report_context = super(FamilyEquivalentReport, cls).get_context(
|
||||
records, data)
|
||||
|
||||
report_context['company'] = Company(Transaction().context['company'])
|
||||
report_context['records'] = cls._get_family_records(records)
|
||||
report_context['compute_qty'] = cls.compute_qty
|
||||
return report_context
|
||||
|
||||
@classmethod
|
||||
def _get_family_records(cls, records):
|
||||
pool = Pool()
|
||||
Location = pool.get('stock.location')
|
||||
Date_ = pool.get('ir.date')
|
||||
FamilyEquivalent = pool.get('lims.family.equivalent')
|
||||
|
||||
locations = Location.search([
|
||||
('type', '=', 'storage'),
|
||||
])
|
||||
context = {}
|
||||
context['locations'] = [l.id for l in locations]
|
||||
context['stock_date_end'] = Date_.today()
|
||||
|
||||
with Transaction().set_context(context):
|
||||
res = FamilyEquivalent.browse(records)
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def compute_qty(cls, from_uom, qty, to_uom):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
return Uom.compute_qty(from_uom, qty, to_uom)
|
|
@ -1,45 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Groups -->
|
||||
|
||||
<record model="res.group" id="group_lims_conf_material_readonly">
|
||||
<field name="name">Lims Configuration Material Read Only</field>
|
||||
</record>
|
||||
<record model="res.group" id="group_lims_conf_material_admin">
|
||||
<field name="name">Lims Configuration Material Admin</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lims_conf_material_admin">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_conf_material_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="res.group" id="group_lims_lot_input_prod">
|
||||
<field name="name">Lims Lot Input for production</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lot_input_prod">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_lot_input_prod"/>
|
||||
</record>
|
||||
|
||||
<record model="res.group" id="group_lims_lot_prod_sale">
|
||||
<field name="name">Lims Lot Production for sale</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lot_prod_sale">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_lot_prod_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="res.group" id="group_lims_lot_domestic_use">
|
||||
<field name="name">Lims Lot Production for domestic use</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lot_domestic_use">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_lot_domestic_use"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -10,12 +10,11 @@ from trytond.model import ModelView, ModelSQL, fields
|
|||
from trytond.pyson import PYSONEncoder, Eval, Equal, Bool, Not
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pool import PoolMeta, Pool
|
||||
from trytond.wizard import Wizard, StateTransition, StateAction
|
||||
from trytond.wizard import Wizard, StateAction
|
||||
from trytond.modules.product import price_digits
|
||||
|
||||
__all__ = ['PurityDegree', 'Brand', 'FamilyEquivalent', 'Template', 'Product',
|
||||
'UpdateCostPrice', 'LotCategory', 'Lot', 'Move', 'ShipmentIn',
|
||||
'LimsMoveProductionRelated']
|
||||
'LotCategory', 'Lot', 'Move', 'ShipmentIn', 'MoveProductionRelated']
|
||||
|
||||
|
||||
class PurityDegree(ModelSQL, ModelView):
|
||||
|
@ -220,8 +219,8 @@ class Product:
|
|||
qty = Decimal(str(qty))
|
||||
if move.from_location.type == 'storage':
|
||||
qty *= -1
|
||||
if (move.from_location.type in ['supplier', 'production']
|
||||
or move.to_location.type == 'supplier'):
|
||||
if (move.from_location.type in ['supplier', 'production'] or
|
||||
move.to_location.type == 'supplier'):
|
||||
with Transaction().set_context(date=move.effective_date):
|
||||
unit_price = Currency.compute(
|
||||
move.currency, move.unit_price,
|
||||
|
@ -255,34 +254,6 @@ class Product:
|
|||
return [('template.' + name,) + tuple(clause[1:])]
|
||||
|
||||
|
||||
class UpdateCostPrice:
|
||||
__name__ = 'product.update_cost_price'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
start_state = 'check'
|
||||
check = StateTransition()
|
||||
|
||||
def transition_check(self):
|
||||
context = Transaction().context
|
||||
if context['active_model'] == 'product.template':
|
||||
return 'ask_price'
|
||||
return 'end'
|
||||
|
||||
def default_ask_price(self, fields):
|
||||
Template = Pool().get('product.template')
|
||||
default = super(UpdateCostPrice, self).default_ask_price(fields)
|
||||
if 'template' in default:
|
||||
template = Template(default['template'])
|
||||
default['cost_price'] = template.cost_price
|
||||
return default
|
||||
|
||||
def transition_update_price(self):
|
||||
Template = Pool().get('product.template')
|
||||
write = partial(Template.write, [self.ask_price.template])
|
||||
write({'cost_price': self.ask_price.cost_price})
|
||||
return 'end'
|
||||
|
||||
|
||||
class LotCategory(ModelSQL, ModelView):
|
||||
"Lot Category"
|
||||
__name__ = "stock.lot.category"
|
||||
|
@ -302,7 +273,7 @@ class Lot:
|
|||
|
||||
category = fields.Many2One('stock.lot.category', 'Category')
|
||||
special_category = fields.Function(fields.Char('Category'),
|
||||
'on_change_with_special_category', searcher='search_special_category')
|
||||
'on_change_with_special_category')
|
||||
|
||||
stability = fields.Char('Stability', depends=['special_category'],
|
||||
states={
|
||||
|
@ -446,24 +417,24 @@ class Lot:
|
|||
def create(cls, vlist):
|
||||
pool = Pool()
|
||||
Product = pool.get('product.product')
|
||||
LimsConfig = pool.get('lims.configuration')
|
||||
Config = pool.get('lims.configuration')
|
||||
|
||||
lims_config = LimsConfig(1)
|
||||
config = Config(1)
|
||||
vlist = [x.copy() for x in vlist]
|
||||
for values in vlist:
|
||||
if not values.get('category'):
|
||||
product = Product(values['product'])
|
||||
lot_category_id = None
|
||||
if (product.purchasable and not product.salable):
|
||||
lot_category_id = (lims_config.lot_category_input_prod.id
|
||||
if lims_config.lot_category_input_prod else None)
|
||||
lot_category_id = (config.lot_category_input_prod.id
|
||||
if config.lot_category_input_prod else None)
|
||||
elif (not product.purchasable and product.salable):
|
||||
lot_category_id = (lims_config.lot_category_prod_sale.id
|
||||
if lims_config.lot_category_prod_sale else None)
|
||||
lot_category_id = (config.lot_category_prod_sale.id
|
||||
if config.lot_category_prod_sale else None)
|
||||
elif (not product.purchasable and not product.salable):
|
||||
lot_category_id = (
|
||||
lims_config.lot_category_prod_domestic_use.id if
|
||||
lims_config.lot_category_prod_domestic_use else None)
|
||||
config.lot_category_prod_domestic_use.id if
|
||||
config.lot_category_prod_domestic_use else None)
|
||||
if lot_category_id:
|
||||
values['category'] = lot_category_id
|
||||
return super(Lot, cls).create(vlist)
|
||||
|
@ -569,7 +540,7 @@ class ShipmentIn:
|
|||
return move
|
||||
|
||||
|
||||
class LimsMoveProductionRelated(Wizard):
|
||||
class MoveProductionRelated(Wizard):
|
||||
'Related Productions'
|
||||
__name__ = 'lims.move.production_related'
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[tryton]
|
||||
version=4.4.0
|
||||
version=4.8.0
|
||||
depends:
|
||||
lims
|
||||
production
|
||||
|
@ -7,11 +7,6 @@ depends:
|
|||
sale
|
||||
purchase
|
||||
xml:
|
||||
security/users.xml
|
||||
production_view.xml
|
||||
stock_view.xml
|
||||
configuration_view.xml
|
||||
lims_report.xml
|
||||
data/production_sequences.xml
|
||||
lims_menu.xml
|
||||
security/access_rights.xml
|
||||
stock.xml
|
||||
production.xml
|
||||
configuration.xml
|
|
@ -3,7 +3,7 @@
|
|||
<xpath
|
||||
expr="/form/notebook/page[@id='general']"
|
||||
position="after">
|
||||
<page string="Lims" id="lims">
|
||||
<page string="LIMS" id="lims">
|
||||
<label name="common_name"/>
|
||||
<field name="common_name"/>
|
||||
<label name="chemical_name"/>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<data>
|
||||
<xpath
|
||||
expr="/tree/field[@name='active']"
|
||||
expr="/tree/field[@name='name']"
|
||||
position="after">
|
||||
<field name="divide_lots"/>
|
||||
</xpath>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<data>
|
||||
<xpath
|
||||
expr="/form/notebook/page[@id='inventory_moves']/field[@name='inventory_moves']"
|
||||
expr="/form/notebook/page[@name='inventory_moves']/field[@name='inventory_moves']"
|
||||
position="replace_attributes">
|
||||
<field name="inventory_moves" colspan="4" mode="tree,form"
|
||||
view_ids="lims_production.stock_move_in_shipment_view_list,stock.move_view_form"/>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2013-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .project import *
|
||||
from . import project
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
LimsProject,
|
||||
LimsEntry,
|
||||
LimsSample,
|
||||
LimsCreateSampleStart,
|
||||
project.Project,
|
||||
project.Entry,
|
||||
project.Sample,
|
||||
project.CreateSampleStart,
|
||||
module='lims_project', type_='model')
|
||||
Pool.register(
|
||||
LimsCreateSample,
|
||||
project.CreateSample,
|
||||
module='lims_project', type_='wizard')
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Icons -->
|
||||
|
||||
<record model="ir.ui.icon" id="project_icon">
|
||||
<field name="name">lims-project</field>
|
||||
<field name="path">icons/project.svg</field>
|
||||
</record>
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<!-- Configuration / Projects -->
|
||||
<menuitem name="Projects" parent="lims.lims_config"
|
||||
id="lims_config_projects" sequence="60"/>
|
||||
|
||||
<!-- Projects -->
|
||||
<menuitem parent="lims.lims_menu" action="act_lims_project_list"
|
||||
id="lims_project_menu" sequence="20"
|
||||
icon="lims-project"/>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -8,11 +8,10 @@ from trytond.pool import PoolMeta, Pool
|
|||
from trytond.pyson import Eval
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
__all__ = ['LimsProject', 'LimsEntry', 'LimsSample', 'LimsCreateSampleStart',
|
||||
'LimsCreateSample']
|
||||
__all__ = ['Project', 'Entry', 'Sample', 'CreateSampleStart', 'CreateSample']
|
||||
|
||||
|
||||
class LimsProject(ModelSQL, ModelView):
|
||||
class Project(ModelSQL, ModelView):
|
||||
'Project'
|
||||
__name__ = 'lims.project'
|
||||
_rec_name = 'description'
|
||||
|
@ -29,7 +28,7 @@ class LimsProject(ModelSQL, ModelView):
|
|||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(LimsProject, cls).__setup__()
|
||||
super(Project, cls).__setup__()
|
||||
t = cls.__table__()
|
||||
cls._sql_constraints += [
|
||||
('code_uniq', Unique(t, t.code),
|
||||
|
@ -62,7 +61,7 @@ class LimsProject(ModelSQL, ModelView):
|
|||
return [(cls._rec_name,) + tuple(clause[1:])]
|
||||
|
||||
|
||||
class LimsEntry:
|
||||
class Entry:
|
||||
__name__ = 'lims.entry'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -74,7 +73,7 @@ class LimsEntry:
|
|||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(LimsEntry, cls).__setup__()
|
||||
super(Entry, cls).__setup__()
|
||||
cls.samples.context.update({
|
||||
'project': Eval('project', None),
|
||||
})
|
||||
|
@ -89,7 +88,7 @@ class LimsEntry:
|
|||
return res
|
||||
|
||||
|
||||
class LimsSample:
|
||||
class Sample:
|
||||
__name__ = 'lims.sample'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -98,9 +97,9 @@ class LimsSample:
|
|||
|
||||
@staticmethod
|
||||
def default_project_type():
|
||||
LimsProject = Pool().get('lims.project')
|
||||
Project = Pool().get('lims.project')
|
||||
if Transaction().context.get('project'):
|
||||
return LimsProject(Transaction().context.get('project')).type
|
||||
return Project(Transaction().context.get('project')).type
|
||||
return ''
|
||||
|
||||
@fields.depends('entry')
|
||||
|
@ -111,24 +110,24 @@ class LimsSample:
|
|||
return res
|
||||
|
||||
|
||||
class LimsCreateSampleStart:
|
||||
class CreateSampleStart:
|
||||
__name__ = 'lims.create_sample.start'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
project_type = fields.Char('Type')
|
||||
|
||||
|
||||
class LimsCreateSample:
|
||||
class CreateSample:
|
||||
__name__ = 'lims.create_sample'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
def default_start(self, fields):
|
||||
LimsEntry = Pool().get('lims.entry')
|
||||
Entry = Pool().get('lims.entry')
|
||||
|
||||
defaults = super(LimsCreateSample, self).default_start(fields)
|
||||
defaults = super(CreateSample, self).default_start(fields)
|
||||
defaults['project_type'] = ''
|
||||
|
||||
entry = LimsEntry(Transaction().context['active_id'])
|
||||
entry = Entry(Transaction().context['active_id'])
|
||||
if entry.project:
|
||||
defaults['project_type'] = entry.project.type
|
||||
return defaults
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Groups -->
|
||||
|
||||
<record model="res.group" id="group_lims_conf_project_readonly">
|
||||
<field name="name">Lims Configuration Projects Read Only</field>
|
||||
</record>
|
||||
<record model="res.group" id="group_lims_conf_project_admin">
|
||||
<field name="name">Lims Configuration Projects Admin</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lims_conf_project_admin">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_conf_project_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="res.group" id="group_lims_project_readonly">
|
||||
<field name="name">Lims Projects Read Only</field>
|
||||
</record>
|
||||
<record model="res.group" id="group_lims_project">
|
||||
<field name="name">Lims Projects</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lims_project">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_project"/>
|
||||
</record>
|
||||
|
||||
<!-- Project -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_project_view_form">
|
||||
<field name="model">lims.project</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">project_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_project_view_list">
|
||||
<field name="model">lims.project</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">project_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_lims_project_list">
|
||||
<field name="name">Projects</field>
|
||||
<field name="res_model">lims.project</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_lims_project_view_list">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="lims_project_view_list"/>
|
||||
<field name="act_window" ref="act_lims_project_list"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_lims_project_view_form">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="lims_project_view_form"/>
|
||||
<field name="act_window" ref="act_lims_project_list"/>
|
||||
</record>
|
||||
|
||||
<!-- Entry -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_entry_view_form">
|
||||
<field name="model">lims.entry</field>
|
||||
<field name="inherit" ref="lims.lims_entry_view_form"/>
|
||||
<field name="name">entry_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_entry_view_list">
|
||||
<field name="model">lims.entry</field>
|
||||
<field name="inherit" ref="lims.lims_entry_view_list"/>
|
||||
<field name="name">entry_list</field>
|
||||
</record>
|
||||
|
||||
<!-- Icons -->
|
||||
|
||||
<record model="ir.ui.icon" id="project_icon">
|
||||
<field name="name">lims-project</field>
|
||||
<field name="path">icons/project.svg</field>
|
||||
</record>
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<!-- Configuration / Projects -->
|
||||
<menuitem name="Projects" parent="lims.lims_config"
|
||||
id="lims_config_projects" sequence="60"/>
|
||||
|
||||
<!-- Projects -->
|
||||
<menuitem parent="lims.lims_laboratory" action="act_lims_project_list"
|
||||
id="lims_project_menu" sequence="20"
|
||||
icon="lims-project"/>
|
||||
|
||||
<!-- Access Rights on Models -->
|
||||
|
||||
<record model="ir.model.access" id="access_project">
|
||||
<field name="model" search="[('model', '=', 'lims.project')]"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_project_group_project">
|
||||
<field name="model" search="[('model', '=', 'lims.project')]"/>
|
||||
<field name="group" ref="group_lims_project"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<!-- Access Rights on Menu -->
|
||||
|
||||
<!-- Configuration / Projects -->
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_laboratory_group_conf_project_readonly">
|
||||
<field name="menu" ref="lims.lims_laboratory"/>
|
||||
<field name="group" ref="group_lims_conf_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_laboratory_group_conf_project_admin">
|
||||
<field name="menu" ref="lims.lims_laboratory"/>
|
||||
<field name="group" ref="group_lims_conf_project_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_config_group_conf_project_readonly">
|
||||
<field name="menu" ref="lims.lims_config"/>
|
||||
<field name="group" ref="group_lims_conf_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_config_group_conf_project_admin">
|
||||
<field name="menu" ref="lims.lims_config"/>
|
||||
<field name="group" ref="group_lims_conf_project_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_config_projects_group_conf_project_readonly">
|
||||
<field name="menu" ref="lims_config_projects"/>
|
||||
<field name="group" ref="group_lims_conf_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_config_projects_group_conf_project_admin">
|
||||
<field name="menu" ref="lims_config_projects"/>
|
||||
<field name="group" ref="group_lims_conf_project_admin"/>
|
||||
</record>
|
||||
|
||||
<!-- Projects -->
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_laboratory_group_project_readonly">
|
||||
<field name="menu" ref="lims.lims_laboratory"/>
|
||||
<field name="group" ref="group_lims_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_laboratory_group_project">
|
||||
<field name="menu" ref="lims.lims_laboratory"/>
|
||||
<field name="group" ref="group_lims_project"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_project_group_project_readonly">
|
||||
<field name="menu" ref="lims_project_menu"/>
|
||||
<field name="group" ref="group_lims_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_project_group_project">
|
||||
<field name="menu" ref="lims_project_menu"/>
|
||||
<field name="group" ref="group_lims_project"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,49 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Menu items in lims_menu.xml -->
|
||||
|
||||
<!-- Project -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_project_view_form">
|
||||
<field name="model">lims.project</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">project_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_project_view_list">
|
||||
<field name="model">lims.project</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">project_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_lims_project_list">
|
||||
<field name="name">Projects</field>
|
||||
<field name="res_model">lims.project</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_lims_project_view_list">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="lims_project_view_list"/>
|
||||
<field name="act_window" ref="act_lims_project_list"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_lims_project_view_form">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="lims_project_view_form"/>
|
||||
<field name="act_window" ref="act_lims_project_list"/>
|
||||
</record>
|
||||
|
||||
<!-- Entry -->
|
||||
|
||||
<record model="ir.ui.view" id="lims_entry_view_form">
|
||||
<field name="model">lims.entry</field>
|
||||
<field name="inherit" ref="lims.lims_entry_view_form"/>
|
||||
<field name="name">entry_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="lims_entry_view_list">
|
||||
<field name="model">lims.entry</field>
|
||||
<field name="inherit" ref="lims.lims_entry_view_list"/>
|
||||
<field name="name">entry_list</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,77 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Access Rights on Models -->
|
||||
|
||||
<record model="ir.model.access" id="access_project">
|
||||
<field name="model" search="[('model', '=', 'lims.project')]"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_project_group_project">
|
||||
<field name="model" search="[('model', '=', 'lims.project')]"/>
|
||||
<field name="group" ref="group_lims_project"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<!-- Access Rights on Menu -->
|
||||
|
||||
<!-- Configuration / Projects -->
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_group_conf_project_readonly">
|
||||
<field name="menu" ref="lims.lims_menu"/>
|
||||
<field name="group" ref="group_lims_conf_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_group_conf_project_admin">
|
||||
<field name="menu" ref="lims.lims_menu"/>
|
||||
<field name="group" ref="group_lims_conf_project_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_config_group_conf_project_readonly">
|
||||
<field name="menu" ref="lims.lims_config"/>
|
||||
<field name="group" ref="group_lims_conf_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_config_group_conf_project_admin">
|
||||
<field name="menu" ref="lims.lims_config"/>
|
||||
<field name="group" ref="group_lims_conf_project_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_config_projects_group_conf_project_readonly">
|
||||
<field name="menu" ref="lims_config_projects"/>
|
||||
<field name="group" ref="group_lims_conf_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_config_projects_group_conf_project_admin">
|
||||
<field name="menu" ref="lims_config_projects"/>
|
||||
<field name="group" ref="group_lims_conf_project_admin"/>
|
||||
</record>
|
||||
|
||||
<!-- Projects -->
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_group_project_readonly">
|
||||
<field name="menu" ref="lims.lims_menu"/>
|
||||
<field name="group" ref="group_lims_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_lims_group_project">
|
||||
<field name="menu" ref="lims.lims_menu"/>
|
||||
<field name="group" ref="group_lims_project"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_project_group_project_readonly">
|
||||
<field name="menu" ref="lims_project_menu"/>
|
||||
<field name="group" ref="group_lims_project_readonly"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu-res.group" id="menu_project_group_project">
|
||||
<field name="menu" ref="lims_project_menu"/>
|
||||
<field name="group" ref="group_lims_project"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,32 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Groups -->
|
||||
|
||||
<record model="res.group" id="group_lims_conf_project_readonly">
|
||||
<field name="name">Lims Configuration Projects Read Only</field>
|
||||
</record>
|
||||
<record model="res.group" id="group_lims_conf_project_admin">
|
||||
<field name="name">Lims Configuration Projects Admin</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lims_conf_project_admin">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_conf_project_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="res.group" id="group_lims_project_readonly">
|
||||
<field name="name">Lims Projects Read Only</field>
|
||||
</record>
|
||||
<record model="res.group" id="group_lims_project">
|
||||
<field name="name">Lims Projects</field>
|
||||
</record>
|
||||
<record model="res.user-res.group" id="user_admin_group_lims_project">
|
||||
<field name="user" ref="res.user_admin"/>
|
||||
<field name="group" ref="group_lims_project"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,9 +1,6 @@
|
|||
[tryton]
|
||||
version=4.4.0
|
||||
version=4.8.0
|
||||
depends:
|
||||
lims
|
||||
xml:
|
||||
security/users.xml
|
||||
project_view.xml
|
||||
lims_menu.xml
|
||||
security/access_rights.xml
|
||||
project.xml
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2013-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .project import *
|
||||
from . import project
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
LimsProject,
|
||||
LimsEntry,
|
||||
project.Project,
|
||||
project.Entry,
|
||||
module='lims_project_interlaboratory', type_='model')
|
||||
|
|
|
@ -7,7 +7,7 @@ from trytond.model import fields
|
|||
from trytond.pool import PoolMeta
|
||||
from trytond.pyson import Eval, Equal, Bool, Not, And
|
||||
|
||||
__all__ = ['LimsProject', 'LimsEntry']
|
||||
__all__ = ['Project', 'Entry']
|
||||
|
||||
STATES = {
|
||||
'required': Bool(Equal(Eval('type'), 'itl')),
|
||||
|
@ -16,7 +16,7 @@ DEPENDS = ['type']
|
|||
PROJECT_TYPE = ('itl', 'Interlaboratory')
|
||||
|
||||
|
||||
class LimsProject:
|
||||
class Project:
|
||||
__name__ = 'lims.project'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -32,26 +32,26 @@ class LimsProject:
|
|||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(LimsProject, cls).__setup__()
|
||||
super(Project, cls).__setup__()
|
||||
project_type = PROJECT_TYPE
|
||||
if project_type not in cls.type.selection:
|
||||
cls.type.selection.append(project_type)
|
||||
|
||||
@classmethod
|
||||
def view_attributes(cls):
|
||||
return super(LimsProject, cls).view_attributes() + [
|
||||
return super(Project, cls).view_attributes() + [
|
||||
('//group[@id="itl"]', 'states', {
|
||||
'invisible': Not(Bool(Equal(Eval('type'), 'itl'))),
|
||||
})]
|
||||
|
||||
|
||||
class LimsEntry:
|
||||
class Entry:
|
||||
__name__ = 'lims.entry'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(LimsEntry, cls).__setup__()
|
||||
super(Entry, cls).__setup__()
|
||||
project_type = PROJECT_TYPE
|
||||
if project_type not in cls.project_type.selection:
|
||||
cls.project_type.selection.append(project_type)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[tryton]
|
||||
version=4.4.0
|
||||
version=4.8.0
|
||||
depends:
|
||||
lims_project
|
||||
xml:
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Version 4.4.0 - 2017-10-08
|
|
@ -1,5 +1,5 @@
|
|||
Copyright (C) 2017 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2017 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2017-2018 Ignacio Parszyk <iparszyk@kalenislims.com>
|
||||
Copyright (C) 2013-2018 Sebastián Marró <smarro@kalenislims.com>
|
||||
Copyright (C) 2013-2016 Luis Falcon <falcon@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -3,61 +3,59 @@
|
|||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .configuration import *
|
||||
from .project import *
|
||||
from report import *
|
||||
from wizard import *
|
||||
from . import configuration
|
||||
from . import project
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
LimsConfiguration,
|
||||
LimsConfigurationSequence,
|
||||
LimsLabWorkYear,
|
||||
LimsLabWorkYearSequence,
|
||||
LimsProject,
|
||||
LimsEntry,
|
||||
LimsProjectReferenceElement,
|
||||
LimsProjectSolventAndReagent,
|
||||
LimsProjectSampleInCustody,
|
||||
LimsProjectDeviationAndAmendment,
|
||||
LimsProjectDeviationAndAmendmentProfessional,
|
||||
LimsProjectChangeLog,
|
||||
LimsSample,
|
||||
LimsCreateSampleStart,
|
||||
LimsProjectProfessionalPosition,
|
||||
LimsProjectLaboratoryProfessional,
|
||||
Lot,
|
||||
LimsProjectReOpenStart,
|
||||
LimsProjectGLPReport03PrintStart,
|
||||
LimsProjectGLPReport05PrintStart,
|
||||
LimsProjectGLPReport10PrintStart,
|
||||
LimsProjectGLPReport12PrintStart,
|
||||
configuration.Configuration,
|
||||
configuration.ConfigurationSequence,
|
||||
configuration.LabWorkYear,
|
||||
configuration.LabWorkYearSequence,
|
||||
project.Project,
|
||||
project.Entry,
|
||||
project.ProjectReferenceElement,
|
||||
project.ProjectSolventAndReagent,
|
||||
project.ProjectSampleInCustody,
|
||||
project.ProjectDeviationAndAmendment,
|
||||
project.ProjectDeviationAndAmendmentProfessional,
|
||||
project.ProjectChangeLog,
|
||||
project.Sample,
|
||||
project.CreateSampleStart,
|
||||
project.ProjectProfessionalPosition,
|
||||
project.ProjectLaboratoryProfessional,
|
||||
project.Lot,
|
||||
project.ProjectReOpenStart,
|
||||
project.ProjectGLPReport03PrintStart,
|
||||
project.ProjectGLPReport05PrintStart,
|
||||
project.ProjectGLPReport10PrintStart,
|
||||
project.ProjectGLPReport12PrintStart,
|
||||
module='lims_project_study_plan', type_='model')
|
||||
Pool.register(
|
||||
LimsCreateSample,
|
||||
LimsProjectReOpen,
|
||||
LimsProjectGLPReport03Print,
|
||||
LimsProjectGLPReport05Print,
|
||||
LimsProjectGLPReport10Print,
|
||||
LimsProjectGLPReport12Print,
|
||||
project.CreateSample,
|
||||
project.ProjectReOpen,
|
||||
project.ProjectGLPReport03Print,
|
||||
project.ProjectGLPReport05Print,
|
||||
project.ProjectGLPReport10Print,
|
||||
project.ProjectGLPReport12Print,
|
||||
module='lims_project_study_plan', type_='wizard')
|
||||
Pool.register(
|
||||
LimsProjectGLPReport01,
|
||||
LimsProjectGLPReport02,
|
||||
LimsProjectGLPReport03,
|
||||
LimsProjectGLPReport04,
|
||||
LimsProjectGLPReport05,
|
||||
LimsProjectGLPReport06,
|
||||
LimsProjectGLPReport07,
|
||||
LimsProjectGLPReport08,
|
||||
LimsProjectGLPReport09,
|
||||
LimsProjectGLPReport10,
|
||||
LimsProjectGLPReport11,
|
||||
LimsProjectGLPReport12,
|
||||
LimsProjectGLPReport13,
|
||||
LimsProjectGLPReportStudyPlan,
|
||||
LimsProjectGLPReportFinalRP,
|
||||
LimsProjectGLPReportFinalFOR,
|
||||
LimsProjectGLPReportAnalyticalPhase,
|
||||
project.ProjectGLPReport01,
|
||||
project.ProjectGLPReport02,
|
||||
project.ProjectGLPReport03,
|
||||
project.ProjectGLPReport04,
|
||||
project.ProjectGLPReport05,
|
||||
project.ProjectGLPReport06,
|
||||
project.ProjectGLPReport07,
|
||||
project.ProjectGLPReport08,
|
||||
project.ProjectGLPReport09,
|
||||
project.ProjectGLPReport10,
|
||||
project.ProjectGLPReport11,
|
||||
project.ProjectGLPReport12,
|
||||
project.ProjectGLPReport13,
|
||||
project.ProjectGLPReportStudyPlan,
|
||||
project.ProjectGLPReportFinalRP,
|
||||
project.ProjectGLPReportFinalFOR,
|
||||
project.ProjectGLPReportAnalyticalPhase,
|
||||
module='lims_project_study_plan', type_='report')
|
||||
|
|
|
@ -3,16 +3,15 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains
|
||||
# the full copyright notices and license terms.
|
||||
|
||||
from trytond import backend
|
||||
from trytond.model import fields
|
||||
from trytond.pool import PoolMeta, Pool
|
||||
from trytond.pyson import Eval
|
||||
|
||||
__all__ = ['LimsConfiguration', 'LimsConfigurationSequence',
|
||||
'LimsLabWorkYear', 'LimsLabWorkYearSequence']
|
||||
__all__ = ['Configuration', 'ConfigurationSequence', 'LabWorkYear',
|
||||
'LabWorkYearSequence']
|
||||
|
||||
|
||||
class LimsConfiguration:
|
||||
class Configuration:
|
||||
__name__ = 'lims.configuration'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -29,7 +28,7 @@ class LimsConfiguration:
|
|||
pool = Pool()
|
||||
if field == 'sample_in_custody_sequence':
|
||||
return pool.get('lims.configuration.sequence')
|
||||
return super(LimsConfiguration, cls).multivalue_model(field)
|
||||
return super(Configuration, cls).multivalue_model(field)
|
||||
|
||||
@classmethod
|
||||
def default_sample_in_custody_sequence(cls, **pattern):
|
||||
|
@ -37,7 +36,7 @@ class LimsConfiguration:
|
|||
'sample_in_custody_sequence').default_sample_in_custody_sequence()
|
||||
|
||||
|
||||
class LimsConfigurationSequence:
|
||||
class ConfigurationSequence:
|
||||
__name__ = 'lims.configuration.sequence'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -58,7 +57,7 @@ class LimsConfigurationSequence:
|
|||
return None
|
||||
|
||||
|
||||
class LimsLabWorkYear:
|
||||
class LabWorkYear:
|
||||
__name__ = 'lims.lab.workyear'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
@ -75,10 +74,10 @@ class LimsLabWorkYear:
|
|||
pool = Pool()
|
||||
if field == 'project_study_plan_sequence':
|
||||
return pool.get('lims.lab.workyear.sequence')
|
||||
return super(LimsLabWorkYear, cls).multivalue_model(field)
|
||||
return super(LabWorkYear, cls).multivalue_model(field)
|
||||
|
||||
|
||||
class LimsLabWorkYearSequence:
|
||||
class LabWorkYearSequence:
|
||||
__name__ = 'lims.lab.workyear.sequence'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<tryton>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Sequences for Sample in Custody -->
|
||||
|
||||
<record model="ir.sequence.type" id="seq_type_sample_in_custody">
|
||||
<field name="name">Sample in Custody</field>
|
||||
<field name="code">lims.project.sample_in_custody</field>
|
||||
</record>
|
||||
<record model="ir.sequence.type-res.group"
|
||||
id="seq_type_sample_in_custody_group_admin">
|
||||
<field name="sequence_type" ref="seq_type_sample_in_custody"/>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
</record>
|
||||
<record model="ir.sequence" id="seq_sample_in_custody">
|
||||
<field name="name">Sample in Custody</field>
|
||||
<field name="code">lims.project.sample_in_custody</field>
|
||||
</record>
|
||||
|
||||
<!-- Sequences for Project -->
|
||||
|
||||
<record model="ir.sequence.type" id="seq_type_stp_project">
|
||||
<field name="name">Project</field>
|
||||
<field name="code">lims.project</field>
|
||||
</record>
|
||||
<record model="ir.sequence.type-res.group"
|
||||
id="seq_type_stp_project_group_admin">
|
||||
<field name="sequence_type" ref="seq_type_stp_project"/>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<!-- Configuration / Projects / Professional Positions -->
|
||||
<menuitem parent="lims_project.lims_config_projects"
|
||||
action="act_lims_project_stp_professional_position_list"
|
||||
id="lims_project_stp_professional_position_menu" sequence="20"/>
|
||||
|
||||
</data>
|
||||
</tryton>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue