diff --git a/lims/CHANGELOG b/lims/CHANGELOG deleted file mode 100644 index da77600..0000000 --- a/lims/CHANGELOG +++ /dev/null @@ -1 +0,0 @@ -Version 4.4.0 - 2017-10-08 diff --git a/lims/analysis.py b/lims/analysis.py index a6ef5f5..67b142b 100644 --- a/lims/analysis.py +++ b/lims/analysis.py @@ -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() diff --git a/lims/report/__init__.py b/lims/report/__init__.py deleted file mode 100644 index a87245d..0000000 --- a/lims/report/__init__.py +++ /dev/null @@ -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 * diff --git a/lims_account_invoice/CHANGELOG b/lims_account_invoice/CHANGELOG deleted file mode 100644 index da77600..0000000 --- a/lims_account_invoice/CHANGELOG +++ /dev/null @@ -1 +0,0 @@ -Version 4.4.0 - 2017-10-08 diff --git a/lims_analytic/CHANGELOG b/lims_analytic/CHANGELOG deleted file mode 100644 index da77600..0000000 --- a/lims_analytic/CHANGELOG +++ /dev/null @@ -1 +0,0 @@ -Version 4.4.0 - 2017-10-08 diff --git a/lims_analytic/COPYRIGHT b/lims_analytic/COPYRIGHT index f9a0b3d..cee46ce 100644 --- a/lims_analytic/COPYRIGHT +++ b/lims_analytic/COPYRIGHT @@ -1,5 +1,5 @@ -Copyright (C) 2017 Ignacio Parszyk -Copyright (C) 2015-2017 Sebastián Marró +Copyright (C) 2017-2018 Ignacio Parszyk +Copyright (C) 2015-2018 Sebastián Marró Copyright (C) 2015-2016 Luis Falcon This program is free software: you can redistribute it and/or modify diff --git a/lims_analytic/__init__.py b/lims_analytic/__init__.py index 83995c7..f82732c 100644 --- a/lims_analytic/__init__.py +++ b/lims_analytic/__init__.py @@ -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') diff --git a/lims_analytic/tryton.cfg b/lims_analytic/tryton.cfg index b983891..fcf8331 100644 --- a/lims_analytic/tryton.cfg +++ b/lims_analytic/tryton.cfg @@ -1,5 +1,5 @@ [tryton] -version=4.4.0 +version=4.8.0 depends: lims analytic_account diff --git a/lims_digital_sign/CHANGELOG b/lims_digital_sign/CHANGELOG deleted file mode 100644 index da77600..0000000 --- a/lims_digital_sign/CHANGELOG +++ /dev/null @@ -1 +0,0 @@ -Version 4.4.0 - 2017-10-08 diff --git a/lims_digital_sign/COPYRIGHT b/lims_digital_sign/COPYRIGHT index de5dc3c..fcbf448 100644 --- a/lims_digital_sign/COPYRIGHT +++ b/lims_digital_sign/COPYRIGHT @@ -1,5 +1,5 @@ -Copyright (C) 2017 Ignacio Parszyk -Copyright (C) 2015-2017 Sebastián Marró +Copyright (C) 2017-2018 Ignacio Parszyk +Copyright (C) 2015-2018 Sebastián Marró Copyright (C) 2015 Bruno M. Villasanti Copyright (C) 2015-2016 Luis Falcon diff --git a/lims_digital_sign/__init__.py b/lims_digital_sign/__init__.py index 10296b3..5ff7529 100644 --- a/lims_digital_sign/__init__.py +++ b/lims_digital_sign/__init__.py @@ -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') diff --git a/lims_digital_sign/configuration.py b/lims_digital_sign/configuration.py index da67fb7..56bceb5 100644 --- a/lims_digital_sign/configuration.py +++ b/lims_digital_sign/configuration.py @@ -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 diff --git a/lims_digital_sign/configuration_view.xml b/lims_digital_sign/configuration.xml similarity index 70% rename from lims_digital_sign/configuration_view.xml rename to lims_digital_sign/configuration.xml index 7ce37cb..e7cdf1a 100644 --- a/lims_digital_sign/configuration_view.xml +++ b/lims_digital_sign/configuration.xml @@ -1,6 +1,4 @@ - diff --git a/lims_digital_sign/wizard/digital_sign.py b/lims_digital_sign/digital_sign.py similarity index 94% rename from lims_digital_sign/wizard/digital_sign.py rename to lims_digital_sign/digital_sign.py index 70532a6..6807398 100644 --- a/lims_digital_sign/wizard/digital_sign.py +++ b/lims_digital_sign/digital_sign.py @@ -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 diff --git a/lims_digital_sign/digital_sign.xml b/lims_digital_sign/digital_sign.xml new file mode 100644 index 0000000..6f68aec --- /dev/null +++ b/lims_digital_sign/digital_sign.xml @@ -0,0 +1,121 @@ + + + + + + + + Lims Digital Sign + + + + + + + + + + user_cron_digital_sign + Cron Lims Digital Sign + + + + + + + + + + + + Lims Digital Sign Results Reports + + + + + days + + + lims.results_report + cron_digital_signs + + + + + + lims_digital_sign.digital_sign.start + form + digital_sign_start_form + + + + lims_digital_sign.digital_sign.succeed + form + digital_sign_succeed_form + + + + lims_digital_sign.digital_sign.failed + form + digital_sign_failed_form + + + + Digital Sign + lims_digital_sign.digital_sign + + + form_action + lims.results_report,-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + lims.results_report + + results_report_list + + + + + + lims-digital_sign + icons/digital_sign.svg + + + + + + + + + + + + + diff --git a/lims_digital_sign/digital_sign_view.xml b/lims_digital_sign/digital_sign_view.xml deleted file mode 100644 index 857de87..0000000 --- a/lims_digital_sign/digital_sign_view.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - Lims Digital Sign Results Reports - - - - - days - - - lims.results_report - cron_digital_signs - - - - diff --git a/lims_digital_sign/lims.py b/lims_digital_sign/lims.py index bb56610..ed8c917 100644 --- a/lims_digital_sign/lims.py +++ b/lims_digital_sign/lims.py @@ -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' diff --git a/lims_digital_sign/lims_menu.xml b/lims_digital_sign/lims_menu.xml deleted file mode 100644 index 8fea2d2..0000000 --- a/lims_digital_sign/lims_menu.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - lims-digital_sign - icons/digital_sign.svg - - - - - - - - - diff --git a/lims_digital_sign/lims_view.xml b/lims_digital_sign/lims_view.xml deleted file mode 100644 index ee9ac97..0000000 --- a/lims_digital_sign/lims_view.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - lims.results_report - - results_report_list - - - - diff --git a/lims_digital_sign/security/access_rights.xml b/lims_digital_sign/security/access_rights.xml deleted file mode 100644 index ac694e6..0000000 --- a/lims_digital_sign/security/access_rights.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lims_digital_sign/security/users.xml b/lims_digital_sign/security/users.xml deleted file mode 100644 index 5eb99a1..0000000 --- a/lims_digital_sign/security/users.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - Lims Digital Sign - - - - - - - - - - user_cron_digital_sign - Cron Lims Digital Sign - - - - - - - - - - diff --git a/lims_digital_sign/tryton.cfg b/lims_digital_sign/tryton.cfg index d5509a8..4b7be5a 100644 --- a/lims_digital_sign/tryton.cfg +++ b/lims_digital_sign/tryton.cfg @@ -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 diff --git a/lims_digital_sign/wizard/__init__.py b/lims_digital_sign/wizard/__init__.py deleted file mode 100644 index 51fb93f..0000000 --- a/lims_digital_sign/wizard/__init__.py +++ /dev/null @@ -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 * diff --git a/lims_digital_sign/wizard/digital_sign.xml b/lims_digital_sign/wizard/digital_sign.xml deleted file mode 100644 index e599443..0000000 --- a/lims_digital_sign/wizard/digital_sign.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - lims_digital_sign.digital_sign.start - form - digital_sign_start_form - - - - lims_digital_sign.digital_sign.succeed - form - digital_sign_succeed_form - - - - lims_digital_sign.digital_sign.failed - form - digital_sign_failed_form - - - - Digital Sign - lims_digital_sign.digital_sign - - - form_action - lims.results_report,-1 - - - - - diff --git a/lims_digital_sign/wizard/lims.py b/lims_digital_sign/wizard/lims.py deleted file mode 100644 index 7b4a883..0000000 --- a/lims_digital_sign/wizard/lims.py +++ /dev/null @@ -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' diff --git a/lims_instrument/CHANGELOG b/lims_instrument/CHANGELOG deleted file mode 100644 index da77600..0000000 --- a/lims_instrument/CHANGELOG +++ /dev/null @@ -1 +0,0 @@ -Version 4.4.0 - 2017-10-08 diff --git a/lims_instrument/COPYRIGHT b/lims_instrument/COPYRIGHT index 0ec399e..2fc7779 100644 --- a/lims_instrument/COPYRIGHT +++ b/lims_instrument/COPYRIGHT @@ -1,5 +1,5 @@ -Copyright (C) 2017 Ignacio Parszyk -Copyright (C) 2013-2017 Sebastián Marró +Copyright (C) 2017-2018 Ignacio Parszyk +Copyright (C) 2013-2018 Sebastián Marró Copyright (C) 2013-2016 Luis Falcon This program is free software: you can redistribute it and/or modify diff --git a/lims_instrument/__init__.py b/lims_instrument/__init__.py index 3820521..1775b7c 100644 --- a/lims_instrument/__init__.py +++ b/lims_instrument/__init__.py @@ -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') diff --git a/lims_instrument/doc/index_es.rst b/lims_instrument/doc/index_es.rst deleted file mode 100644 index fb76e80..0000000 --- a/lims_instrument/doc/index_es.rst +++ /dev/null @@ -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. - diff --git a/lims_instrument/lims_menu.xml b/lims_instrument/lims_menu.xml deleted file mode 100644 index 6cd20cd..0000000 --- a/lims_instrument/lims_menu.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - lims-notebook_load_results_file - icons/notebook_load_results_file.svg - - - - - - - - - - - - diff --git a/lims_instrument/resultsimport.py b/lims_instrument/resultsimport.py index a1549b0..4bebff4 100644 --- a/lims_instrument/resultsimport.py +++ b/lims_instrument/resultsimport.py @@ -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())} diff --git a/lims_instrument/wizard/resultsimport.xml b/lims_instrument/resultsimport.xml similarity index 54% rename from lims_instrument/wizard/resultsimport.xml rename to lims_instrument/resultsimport.xml index 886688c..996c728 100644 --- a/lims_instrument/wizard/resultsimport.xml +++ b/lims_instrument/resultsimport.xml @@ -4,6 +4,34 @@ + + + + lims.resultsimport + form + resultsimport_form + + + lims.resultsimport + tree + resultsimport_list + + + + Results Importers + lims.resultsimport + + + + + + + + + + + + @@ -47,5 +75,23 @@ lims.notebook.load_results_file + + + + lims-notebook_load_results_file + icons/notebook_load_results_file.svg + + + + + + + + + + diff --git a/lims_instrument/resultsimport_view.xml b/lims_instrument/resultsimport_view.xml deleted file mode 100644 index cc0f016..0000000 --- a/lims_instrument/resultsimport_view.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - lims.resultsimport - form - resultsimport_form - - - lims.resultsimport - tree - resultsimport_list - - - - Results Importers - lims.resultsimport - - - - - - - - - - - - - - diff --git a/lims_instrument/tryton.cfg b/lims_instrument/tryton.cfg index 3718b16..0c874ea 100644 --- a/lims_instrument/tryton.cfg +++ b/lims_instrument/tryton.cfg @@ -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 \ No newline at end of file diff --git a/lims_instrument/wizard/__init__.py b/lims_instrument/wizard/__init__.py deleted file mode 100644 index bbd218e..0000000 --- a/lims_instrument/wizard/__init__.py +++ /dev/null @@ -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 * diff --git a/lims_instrument/wizard/resultsimport.py b/lims_instrument/wizard/resultsimport.py deleted file mode 100644 index fc87828..0000000 --- a/lims_instrument/wizard/resultsimport.py +++ /dev/null @@ -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())} diff --git a/lims_instrument_custom_set/CHANGELOG b/lims_instrument_custom_set/CHANGELOG deleted file mode 100644 index da77600..0000000 --- a/lims_instrument_custom_set/CHANGELOG +++ /dev/null @@ -1 +0,0 @@ -Version 4.4.0 - 2017-10-08 diff --git a/lims_instrument_custom_set/COPYRIGHT b/lims_instrument_custom_set/COPYRIGHT index eb0eae7..f393c8b 100644 --- a/lims_instrument_custom_set/COPYRIGHT +++ b/lims_instrument_custom_set/COPYRIGHT @@ -1,5 +1,5 @@ -Copyright (C) 2017 Ignacio Parszyk -Copyright (C) 2014-2017 Sebastián Marró +Copyright (C) 2017-2018 Ignacio Parszyk +Copyright (C) 2014-2018 Sebastián Marró Copyright (C) 2014-2016 Luis Falcon This program is free software: you can redistribute it and/or modify diff --git a/lims_instrument_custom_set/__init__.py b/lims_instrument_custom_set/__init__.py index a4cea70..f8e913d 100644 --- a/lims_instrument_custom_set/__init__.py +++ b/lims_instrument_custom_set/__init__.py @@ -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') diff --git a/lims_instrument_custom_set/custom_set_xls.py b/lims_instrument_custom_set/custom_set_xls.py index 63d95cd..bc8929b 100644 --- a/lims_instrument_custom_set/custom_set_xls.py +++ b/lims_instrument_custom_set/custom_set_xls.py @@ -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 diff --git a/lims_instrument_custom_set/doc/analysis_set_sample.xls b/lims_instrument_custom_set/doc/analysis_set_sample.xls deleted file mode 100644 index fdc214b..0000000 Binary files a/lims_instrument_custom_set/doc/analysis_set_sample.xls and /dev/null differ diff --git a/lims_instrument_custom_set/doc/index_es.rst b/lims_instrument_custom_set/doc/index_es.rst deleted file mode 100644 index 8fac816..0000000 --- a/lims_instrument_custom_set/doc/index_es.rst +++ /dev/null @@ -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. diff --git a/lims_instrument_custom_set/resultsimport.py b/lims_instrument_custom_set/resultsimport.py index 23c51ee..49a8b92 100644 --- a/lims_instrument_custom_set/resultsimport.py +++ b/lims_instrument_custom_set/resultsimport.py @@ -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) diff --git a/lims_instrument_custom_set/tryton.cfg b/lims_instrument_custom_set/tryton.cfg index a27cc8e..9cb334e 100644 --- a/lims_instrument_custom_set/tryton.cfg +++ b/lims_instrument_custom_set/tryton.cfg @@ -1,5 +1,5 @@ [tryton] -version=4.4.0 +version=4.8.0 depends: lims_instrument diff --git a/lims_instrument_generic_form/CHANGELOG b/lims_instrument_generic_form/CHANGELOG deleted file mode 100644 index da77600..0000000 --- a/lims_instrument_generic_form/CHANGELOG +++ /dev/null @@ -1 +0,0 @@ -Version 4.4.0 - 2017-10-08 diff --git a/lims_instrument_generic_form/COPYRIGHT b/lims_instrument_generic_form/COPYRIGHT index eb0eae7..f393c8b 100644 --- a/lims_instrument_generic_form/COPYRIGHT +++ b/lims_instrument_generic_form/COPYRIGHT @@ -1,5 +1,5 @@ -Copyright (C) 2017 Ignacio Parszyk -Copyright (C) 2014-2017 Sebastián Marró +Copyright (C) 2017-2018 Ignacio Parszyk +Copyright (C) 2014-2018 Sebastián Marró Copyright (C) 2014-2016 Luis Falcon This program is free software: you can redistribute it and/or modify diff --git a/lims_instrument_generic_form/__init__.py b/lims_instrument_generic_form/__init__.py index e937585..0cd6f34 100644 --- a/lims_instrument_generic_form/__init__.py +++ b/lims_instrument_generic_form/__init__.py @@ -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') diff --git a/lims_instrument_generic_form/doc/generic_form.xls b/lims_instrument_generic_form/doc/generic_form.xls deleted file mode 100644 index b7f8ec4..0000000 Binary files a/lims_instrument_generic_form/doc/generic_form.xls and /dev/null differ diff --git a/lims_instrument_generic_form/generic_form_xls.py b/lims_instrument_generic_form/generic_form_xls.py index a7cb9e9..fc4976a 100644 --- a/lims_instrument_generic_form/generic_form_xls.py +++ b/lims_instrument_generic_form/generic_form_xls.py @@ -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: diff --git a/lims_instrument_generic_form/resultsimport.py b/lims_instrument_generic_form/resultsimport.py index 6e22006..4b175ce 100644 --- a/lims_instrument_generic_form/resultsimport.py +++ b/lims_instrument_generic_form/resultsimport.py @@ -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() diff --git a/lims_instrument_generic_form/tryton.cfg b/lims_instrument_generic_form/tryton.cfg index a27cc8e..9cb334e 100644 --- a/lims_instrument_generic_form/tryton.cfg +++ b/lims_instrument_generic_form/tryton.cfg @@ -1,5 +1,5 @@ [tryton] -version=4.4.0 +version=4.8.0 depends: lims_instrument diff --git a/lims_instrument_generic_service/CHANGELOG b/lims_instrument_generic_service/CHANGELOG deleted file mode 100644 index da77600..0000000 --- a/lims_instrument_generic_service/CHANGELOG +++ /dev/null @@ -1 +0,0 @@ -Version 4.4.0 - 2017-10-08 diff --git a/lims_instrument_generic_service/COPYRIGHT b/lims_instrument_generic_service/COPYRIGHT index eb0eae7..f393c8b 100644 --- a/lims_instrument_generic_service/COPYRIGHT +++ b/lims_instrument_generic_service/COPYRIGHT @@ -1,5 +1,5 @@ -Copyright (C) 2017 Ignacio Parszyk -Copyright (C) 2014-2017 Sebastián Marró +Copyright (C) 2017-2018 Ignacio Parszyk +Copyright (C) 2014-2018 Sebastián Marró Copyright (C) 2014-2016 Luis Falcon This program is free software: you can redistribute it and/or modify diff --git a/lims_instrument_generic_service/__init__.py b/lims_instrument_generic_service/__init__.py index ca1cbe9..c726b61 100644 --- a/lims_instrument_generic_service/__init__.py +++ b/lims_instrument_generic_service/__init__.py @@ -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') diff --git a/lims_instrument_generic_service/generic_service_xls.py b/lims_instrument_generic_service/generic_service_xls.py index 5765ac9..d899d4e 100644 --- a/lims_instrument_generic_service/generic_service_xls.py +++ b/lims_instrument_generic_service/generic_service_xls.py @@ -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: diff --git a/lims_instrument_generic_service/resultsimport.py b/lims_instrument_generic_service/resultsimport.py index d347923..d638da1 100644 --- a/lims_instrument_generic_service/resultsimport.py +++ b/lims_instrument_generic_service/resultsimport.py @@ -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() diff --git a/lims_instrument_generic_service/tryton.cfg b/lims_instrument_generic_service/tryton.cfg index a27cc8e..9cb334e 100644 --- a/lims_instrument_generic_service/tryton.cfg +++ b/lims_instrument_generic_service/tryton.cfg @@ -1,5 +1,5 @@ [tryton] -version=4.4.0 +version=4.8.0 depends: lims_instrument diff --git a/lims_production/CHANGELOG b/lims_production/CHANGELOG deleted file mode 100644 index da77600..0000000 --- a/lims_production/CHANGELOG +++ /dev/null @@ -1 +0,0 @@ -Version 4.4.0 - 2017-10-08 diff --git a/lims_production/COPYRIGHT b/lims_production/COPYRIGHT index 0ec399e..2fc7779 100644 --- a/lims_production/COPYRIGHT +++ b/lims_production/COPYRIGHT @@ -1,5 +1,5 @@ -Copyright (C) 2017 Ignacio Parszyk -Copyright (C) 2013-2017 Sebastián Marró +Copyright (C) 2017-2018 Ignacio Parszyk +Copyright (C) 2013-2018 Sebastián Marró Copyright (C) 2013-2016 Luis Falcon This program is free software: you can redistribute it and/or modify diff --git a/lims_production/__init__.py b/lims_production/__init__.py index 4415909..99e4107 100644 --- a/lims_production/__init__.py +++ b/lims_production/__init__.py @@ -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') diff --git a/lims_production/configuration.py b/lims_production/configuration.py index b3a535a..20d155f 100644 --- a/lims_production/configuration.py +++ b/lims_production/configuration.py @@ -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' diff --git a/lims_production/configuration_view.xml b/lims_production/configuration.xml similarity index 100% rename from lims_production/configuration_view.xml rename to lims_production/configuration.xml diff --git a/lims_production/data/production_sequences.xml b/lims_production/data/production_sequences.xml deleted file mode 100644 index 3493640..0000000 --- a/lims_production/data/production_sequences.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - Lot - stock.lot - - - - - - - Lot - stock.lot - - - - diff --git a/lims_production/lims_menu.xml b/lims_production/lims_menu.xml deleted file mode 100644 index cf72d98..0000000 --- a/lims_production/lims_menu.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/lims_production/lims_report.xml b/lims_production/lims_report.xml deleted file mode 100644 index 64c11ab..0000000 --- a/lims_production/lims_report.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - Family/Equivalents - lims.family.equivalent.report - lims_production/report/family_equivalent.odt - pdf - - - form_print - lims.family.equivalent,-1 - - - - - diff --git a/lims_production/production.py b/lims_production/production.py index d29eaee..d18d0a5 100644 --- a/lims_production/production.py +++ b/lims_production/production.py @@ -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) diff --git a/lims_production/security/access_rights.xml b/lims_production/production.xml similarity index 67% rename from lims_production/security/access_rights.xml rename to lims_production/production.xml index bf281e5..8b43d08 100644 --- a/lims_production/security/access_rights.xml +++ b/lims_production/production.xml @@ -1,9 +1,144 @@ - - + + + + + Lot + stock.lot + + + + + + + Lot + stock.lot + + + + + + Lims Configuration Material Read Only + + + Lims Configuration Material Admin + + + + + + + + Lims Lot Input for production + + + + + + + + Lims Lot Production for sale + + + + + + + + Lims Lot Production for domestic use + + + + + + + + + + production + + production_production_form + + + production + + production_production_list + + + + + + production.bom + + production_bom_form + + + production.bom + + production_bom_list + + + + + + Related Productions + production + + + + + + + + + + + + + + Related Productions + lims.move.production_related + + + form_relate + stock.move,-1 + + + + + + + + + + + + + + + + + + + Family/Equivalents + lims.family.equivalent.report + lims_production/report/family_equivalent.odt + pdf + + + form_print + lims.family.equivalent,-1 + + + @@ -220,12 +355,12 @@ this repository contains the full copyright notices and license terms. --> - - + + - - + + diff --git a/lims_production/production_view.xml b/lims_production/production_view.xml deleted file mode 100644 index f079c72..0000000 --- a/lims_production/production_view.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - production - - production_production_form - - - production - - production_production_list - - - - - - production.bom - - production_bom_form - - - production.bom - - production_bom_list - - - - - - Related Productions - production - - - - - - - - - - - - - - Related Productions - lims.move.production_related - - - form_relate - stock.move,-1 - - - - - diff --git a/lims_production/report/__init__.py b/lims_production/report/__init__.py deleted file mode 100644 index 007b242..0000000 --- a/lims_production/report/__init__.py +++ /dev/null @@ -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 * diff --git a/lims_production/report/lims_report.py b/lims_production/report/lims_report.py deleted file mode 100644 index f8f305c..0000000 --- a/lims_production/report/lims_report.py +++ /dev/null @@ -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) diff --git a/lims_production/security/users.xml b/lims_production/security/users.xml deleted file mode 100644 index 3162815..0000000 --- a/lims_production/security/users.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - Lims Configuration Material Read Only - - - Lims Configuration Material Admin - - - - - - - - Lims Lot Input for production - - - - - - - - Lims Lot Production for sale - - - - - - - - Lims Lot Production for domestic use - - - - - - - - diff --git a/lims_production/stock.py b/lims_production/stock.py index 401c8f5..8625666 100644 --- a/lims_production/stock.py +++ b/lims_production/stock.py @@ -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' diff --git a/lims_production/stock_view.xml b/lims_production/stock.xml similarity index 100% rename from lims_production/stock_view.xml rename to lims_production/stock.xml diff --git a/lims_production/tryton.cfg b/lims_production/tryton.cfg index 3976ca7..c3fcaa9 100644 --- a/lims_production/tryton.cfg +++ b/lims_production/tryton.cfg @@ -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 \ No newline at end of file diff --git a/lims_production/view/product_template_form.xml b/lims_production/view/product_template_form.xml index 0072b64..e5d80fd 100644 --- a/lims_production/view/product_template_form.xml +++ b/lims_production/view/product_template_form.xml @@ -3,7 +3,7 @@ - +