lims: add new wizard to generate results report

This commit is contained in:
Adrián Bernardi 2020-05-22 16:37:29 -03:00
parent a7aa3e0507
commit 5821abbb2a
9 changed files with 698 additions and 80 deletions

View File

@ -173,6 +173,7 @@ def register():
results_report.GenerateResultsReportResultAutExcludedNotebookLine,
results_report.GenerateResultsReportResultMan,
results_report.OpenSamplesPendingReportingStart,
results_report.GenerateReportStart,
certification.DuplicateAnalysisFamilyStart,
results_report.ResultsReportAnnulationStart,
sample.CountersampleStorageStart,
@ -303,6 +304,7 @@ def register():
results_report.DivideReports,
results_report.GenerateResultsReport,
results_report.OpenSamplesPendingReporting,
results_report.GenerateReport,
results_report.PrintResultsReport,
certification.DuplicateAnalysisFamily,
results_report.ServiceResultsReport,

View File

@ -2591,6 +2591,38 @@ msgctxt "field:lims.notebook.add_internal_relations.start,analysis_domain:"
msgid "Internal relations domain"
msgstr "Dominio para Relaciones internas"
msgctxt "field:lims.notebook.generate_results_report.start,corrective:"
msgid "Corrective"
msgstr "Rectificativo"
msgctxt "field:lims.notebook.generate_results_report.start,notebooks:"
msgid "Samples"
msgstr "Muestras"
msgctxt "field:lims.notebook.generate_results_report.start,preliminary:"
msgid "Preliminary"
msgstr "Preliminar"
msgctxt "field:lims.notebook.generate_results_report.start,report:"
msgid "Target Report"
msgstr "Informe destino"
msgctxt "field:lims.notebook.generate_results_report.start,report_domain:"
msgid "Target Report domain"
msgstr "Dominio para Informe destino"
msgctxt "field:lims.notebook.generate_results_report.start,report_readonly:"
msgid "Target Report readonly"
msgstr "Informe destino sólo lectura"
msgctxt "field:lims.notebook.generate_results_report.start,reports_created:"
msgid "Reports created"
msgstr "Informes creados"
msgctxt "field:lims.notebook.generate_results_report.start,type:"
msgid "Type"
msgstr "Tipo"
msgctxt ""
"field:lims.notebook.internal_relations_calc_1.relation,internal_relation:"
msgid "Internal relation"
@ -4684,6 +4716,10 @@ msgctxt "field:lims.results_report,english_report:"
msgid "English report"
msgstr "Informe en inglés"
msgctxt "field:lims.results_report,entry:"
msgid "Entry"
msgstr "Ingreso"
msgctxt "field:lims.results_report,generation_type:"
msgid "Generation type"
msgstr "Tipo de generación"
@ -6691,6 +6727,10 @@ msgctxt "model:ir.action,name:wiz_notebook_evaluate_rules"
msgid "Evaluate Rules"
msgstr "10) Evaluar Reglas de cuaderno"
msgctxt "model:ir.action,name:wiz_notebook_generate_results_report"
msgid "Generate Results Report"
msgstr "Generar informe de resultados"
msgctxt "model:ir.action,name:wiz_notebook_line_evaluate_rules"
msgid "Evaluate Rules"
msgstr "10) Evaluar Reglas de cuaderno"
@ -8383,6 +8423,10 @@ msgctxt "model:lims.notebook.evaluate_rules.start,name:"
msgid "Evaluate Rules"
msgstr "Evaluar Reglas de cuaderno"
msgctxt "model:lims.notebook.generate_results_report.start,name:"
msgid "Generate Results Report"
msgstr "Generar informe de resultados"
msgctxt "model:lims.notebook.initial_concentration_calc.start,name:"
msgid "Initial Concentration Calculation"
msgstr "Cálculo de concentración inicial"
@ -11263,6 +11307,22 @@ msgctxt "selection:lims.laboratory,section:"
msgid "Microbiology"
msgstr "Microbiología"
msgctxt "selection:lims.notebook.generate_results_report.start,type:"
msgid "Complementary"
msgstr "Complementario"
msgctxt "selection:lims.notebook.generate_results_report.start,type:"
msgid "Corrective"
msgstr "Rectificativo"
msgctxt "selection:lims.notebook.generate_results_report.start,type:"
msgid "Final"
msgstr "Final"
msgctxt "selection:lims.notebook.generate_results_report.start,type:"
msgid "Preliminary"
msgstr "Preliminar"
msgctxt ""
"selection:lims.notebook.internal_relations_calc_2.variable,converted_result_modifier:"
msgid "<"
@ -13610,6 +13670,14 @@ msgctxt "wizard_button:lims.notebook.evaluate_rules,start,ok:"
msgid "Ok"
msgstr "Aceptar"
msgctxt "wizard_button:lims.notebook.generate_results_report,start,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:lims.notebook.generate_results_report,start,generate:"
msgid "Generate"
msgstr "Generar"
msgctxt "wizard_button:lims.notebook.initial_concentration_calc,start,end:"
msgid "Cancel"
msgstr "Cancelar"

View File

@ -6,6 +6,7 @@ from io import BytesIO
from datetime import datetime
from PyPDF2 import PdfFileMerger
from trytond import backend
from trytond.model import ModelView, ModelSQL, fields
from trytond.wizard import Wizard, StateTransition, StateView, StateAction, \
Button
@ -28,11 +29,11 @@ __all__ = ['ResultsReport', 'ResultsReportVersion',
'GenerateResultsReportResultAutExcludedNotebook',
'GenerateResultsReportResultAutExcludedNotebookLine',
'GenerateResultsReport', 'OpenSamplesPendingReportingStart',
'OpenSamplesPendingReporting', 'PrintResultsReport',
'ServiceResultsReport', 'FractionResultsReport', 'SampleResultsReport',
'ResultsReportSample', 'ResultsReportAnnulationStart',
'ResultsReportAnnulation', 'ResultReport', 'GlobalResultReport',
'ResultReportTranscription']
'OpenSamplesPendingReporting', 'GenerateReportStart', 'GenerateReport',
'PrintResultsReport', 'ServiceResultsReport', 'FractionResultsReport',
'SampleResultsReport', 'ResultsReportSample',
'ResultsReportAnnulationStart', 'ResultsReportAnnulation', 'ResultReport',
'GlobalResultReport', 'ResultReportTranscription']
def get_print_date():
@ -53,11 +54,24 @@ class ResultsReport(ModelSQL, ModelView):
number = fields.Char('Number', select=True, readonly=True)
versions = fields.One2Many('lims.results_report.version',
'results_report', 'Laboratories', readonly=True)
party = fields.Many2One('party.party', 'Party', readonly=True)
entry = fields.Many2One('lims.entry', 'Entry', readonly=True)
notebook = fields.Many2One('lims.notebook', 'Laboratory notebook')
report_grouper = fields.Integer('Report Grouper')
generation_type = fields.Char('Generation type')
cie_fraction_type = fields.Boolean('QA', readonly=True)
party = fields.Many2One('party.party', 'Party', readonly=True)
notebook = fields.Many2One('lims.notebook', 'Laboratory notebook')
english_report = fields.Boolean('English report')
single_sending_report = fields.Function(fields.Boolean(
'Single sending'), 'get_single_sending_report',
searcher='search_single_sending_report')
single_sending_report_ready = fields.Function(fields.Boolean(
'Single sending Ready'), 'get_single_sending_report_ready')
create_date2 = fields.Function(fields.DateTime('Create Date'),
'get_create_date2', searcher='search_create_date2')
write_date2 = fields.DateTime('Write Date', readonly=True)
attachments = fields.One2Many('ir.attachment', 'resource', 'Attachments')
# PDF Report Cache
report_cache = fields.Binary('Report cache', readonly=True,
file_id='report_cache_id', store_prefix='results_report')
report_cache_id = fields.Char('Report cache id', readonly=True)
@ -66,16 +80,24 @@ class ResultsReport(ModelSQL, ModelView):
file_id='report_cache_eng_id', store_prefix='results_report')
report_cache_eng_id = fields.Char('Report cache id', readonly=True)
report_format_eng = fields.Char('Report format', readonly=True)
single_sending_report = fields.Function(fields.Boolean(
'Single sending'), 'get_single_sending_report',
searcher='search_single_sending_report')
single_sending_report_ready = fields.Function(fields.Boolean(
'Single sending Ready'), 'get_single_sending_report_ready')
english_report = fields.Boolean('English report')
create_date2 = fields.Function(fields.DateTime('Create Date'),
'get_create_date2', searcher='search_create_date2')
write_date2 = fields.DateTime('Write Date', readonly=True)
attachments = fields.One2Many('ir.attachment', 'resource', 'Attachments')
@classmethod
def __register__(cls, module_name):
TableHandler = backend.get('TableHandler')
tablehandler = TableHandler(cls, module_name)
notebook_exist = tablehandler.column_exist('notebook')
entry_exist = tablehandler.column_exist('entry')
super(ResultsReport, cls).__register__(module_name)
if notebook_exist and not entry_exist:
cursor = Transaction().connection.cursor()
cursor.execute('UPDATE "lims_results_report" r '
'SET entry = s.entry '
'FROM "lims_sample" s '
'INNER JOIN "lims_fraction" f ON s.id = f.sample '
'INNER JOIN "lims_notebook" n ON f.id = n.fraction '
'WHERE r.notebook = n.id')
@classmethod
def __setup__(cls):
@ -120,47 +142,42 @@ class ResultsReport(ModelSQL, ModelView):
return [
'number',
'versions',
'party',
'entry',
'notebook',
'report_grouper',
'generation_type',
'cie_fraction_type',
'party',
'notebook',
'english_report',
'attachments',
]
def get_single_sending_report(self, name):
pool = Pool()
Notebook = pool.get('lims.notebook')
if self.notebook:
with Transaction().set_user(0):
notebook = Notebook(self.notebook.id)
return notebook.fraction.sample.entry.single_sending_report
if self.entry:
return self.entry.single_sending_report
return False
@classmethod
def search_single_sending_report(cls, name, clause):
return [('notebook.fraction.sample.entry.' + name,) +
tuple(clause[1:])]
return [('entry.' + name,) + tuple(clause[1:])]
def get_single_sending_report_ready(self, name):
pool = Pool()
Notebook = pool.get('lims.notebook')
EntryDetailAnalysis = pool.get('lims.entry.detail.analysis')
if not self.single_sending_report:
return False
with Transaction().set_user(0):
notebook = Notebook(self.notebook.id)
if EntryDetailAnalysis.search([
('fraction', '=', notebook.fraction.id),
('report', '=', True),
('report_grouper', '=', self.report_grouper),
('state', '!=', 'reported'),
]):
return False
return True
@classmethod
def get_single_sending_report_ready(cls, reports, name):
EntryDetailAnalysis = Pool().get('lims.entry.detail.analysis')
result = {}
for r in reports:
if not r.single_sending_report or not not r.entry:
result[r.id] = False
elif EntryDetailAnalysis.search_count([
('entry', '=', r.entry),
('report_grouper', '=', r.report_grouper),
('report', '=', True),
('state', '!=', 'reported'),
]) > 0:
result[r.id] = False
else:
result[r.id] = True
return result
def get_create_date2(self, name):
return self.create_date.replace(microsecond=0)
@ -587,44 +604,46 @@ class ResultsReportVersionDetail(ModelSQL, ModelView):
@classmethod
@ModelView.button
def release(cls, details):
ResultsLine = Pool().get('lims.results_report.version.detail.line')
ResultsSample = Pool().get('lims.results_report.version.detail.sample')
cls.link_notebook_lines(details)
for detail in details:
defaults = {
'state': 'released',
'valid': True,
'release_uid': int(Transaction().user),
'release_date': datetime.now(),
}
# copy samples from previous valid version
valid_details = cls.search([
('report_version', '=', detail.report_version.id),
('valid', '=', True),
])
if valid_details:
vd_ids = []
samples = []
for vd in valid_details:
vd_ids.append(vd.id)
for sample in vd.samples:
notebook_lines = [
{'notebook_line': nline.notebook_line.id}
for nline in sample.notebook_lines]
samples.append({
'notebook': sample.notebook.id,
'notebook_lines': [('create', notebook_lines)],
})
if samples:
defaults['samples'] = [('create', samples)]
for vd in valid_details:
for valid_sample in vd.samples:
sample_default = ResultsSample._get_sample_copy(
valid_sample)
existing_sample = ResultsSample.search([
('version_detail', '=', detail.id),
('notebook', '=', valid_sample.notebook.id),
], limit=1)
if not existing_sample:
sample_default['version_detail'] = detail.id
sample_default['notebook'] = valid_sample.notebook.id
ResultsSample.create([sample_default])
else:
ResultsSample.write(existing_sample, sample_default)
cls.write(valid_details, {
'valid': False,
})
old_lines = ResultsLine.search([
('detail_sample.version_detail.id', 'in', vd_ids),
])
ResultsLine.delete(old_lines)
# delete samples from previous valid version
old_samples = ResultsSample.search([
('version_detail.report_version', '=',
detail.report_version.id),
('version_detail.valid', '=', True),
])
ResultsSample.delete(old_samples)
cls.write([detail], defaults)
cls.write(valid_details, {
'valid': False,
})
cls.write([detail], {
'state': 'released',
'valid': True,
'release_uid': int(Transaction().user),
'release_date': datetime.now(),
})
detail.generate_report()
@classmethod
@ -843,11 +862,12 @@ class ResultsReportVersionDetail(ModelSQL, ModelView):
def get_fraction_comments(cls, details, name):
result = {}
for d in details:
result[d.id] = None
notebook = getattr(d.report_version.results_report,
'notebook', None)
if notebook:
result[d.id] = getattr(notebook, 'fraction_comments')
comments = []
for sample in d.samples:
fraction_comments = sample.notebook.fraction_comments
if fraction_comments:
comments.append(fraction_comments)
result[d.id] = comments and '\n'.join(comments) or None
return result
def get_icon(self, name):
@ -855,6 +875,19 @@ class ResultsReportVersionDetail(ModelSQL, ModelView):
return 'lims-blue'
return 'lims-white'
@classmethod
def _get_detail_copy(cls, detail):
detail_default = {}
detail_default['report_type_forced'] = detail.report_type_forced
detail_default['report_result_type_forced'] = (
detail.report_result_type_forced)
if detail.signer:
detail_default['signer'] = detail.signer.id
if detail.resultrange_origin:
detail_default['resultrange_origin'] = detail.resultrange_origin.id
detail_default['comments'] = str(detail.comments or '')
return detail_default
class ResultsReportVersionDetailSample(ModelSQL, ModelView):
'Results Report Version Detail Sample'
@ -885,6 +918,16 @@ class ResultsReportVersionDetailSample(ModelSQL, ModelView):
result[name][s.id] = getattr(s.notebook, name, None)
return result
@classmethod
def _get_sample_copy(cls, sample):
sample_default = {}
notebook_lines = [
{'notebook_line': nline.notebook_line.id}
for nline in sample.notebook_lines]
if notebook_lines:
sample_default['notebook_lines'] = [('create', notebook_lines)]
return sample_default
class ResultsReportVersionDetailLine(ModelSQL, ModelView):
'Results Report Version Detail Line'
@ -1647,6 +1690,7 @@ class GenerateResultsReport(Wizard):
if line.notebook.id not in notebooks:
notebooks[line.notebook.id] = {
'party': line.notebook.party.id,
'entry': line.notebook.fraction.entry.id,
'notebook': line.notebook.id,
'divided_report': line.notebook.divided_report,
'english_report': (
@ -1676,6 +1720,7 @@ class GenerateResultsReport(Wizard):
}
reports = {
'party': notebook['party'],
'entry': notebook['entry'],
'notebook': notebook['notebook'],
'report_grouper': 0,
'generation_type': 'aut',
@ -1711,6 +1756,7 @@ class GenerateResultsReport(Wizard):
}
reports = {
'party': notebook['party'],
'entry': notebook['entry'],
'notebook': notebook['notebook'],
'report_grouper': grouper,
'generation_type': 'aut',
@ -1907,6 +1953,7 @@ class GenerateResultsReport(Wizard):
if key not in parties:
parties[key] = {
'party': line.notebook.party.id,
'entry': line.notebook.fraction.entry.id,
'english_report': (
line.notebook.fraction.entry.english_report),
'cie_fraction_type': (
@ -1953,6 +2000,7 @@ class GenerateResultsReport(Wizard):
}
reports = {
'party': party['party'],
'entry': party['entry'],
'notebook': None,
'report_grouper': grouper,
'generation_type': 'man',
@ -1971,6 +2019,7 @@ class GenerateResultsReport(Wizard):
if line.notebook.id not in notebooks:
notebooks[line.notebook.id] = {
'party': line.notebook.party.id,
'entry': line.notebook.fraction.entry.id,
'notebook': line.notebook.id,
'divided_report': line.notebook.divided_report,
'english_report': (
@ -2001,6 +2050,7 @@ class GenerateResultsReport(Wizard):
}
reports = {
'party': notebook['party'],
'entry': notebook['entry'],
'notebook': notebook['notebook'],
'report_grouper': 0,
'generation_type': 'man',
@ -2039,6 +2089,7 @@ class GenerateResultsReport(Wizard):
}
reports = {
'party': notebook['party'],
'entry': notebook['entry'],
'notebook': notebook['notebook'],
'report_grouper': grouper,
'generation_type': 'man',
@ -2069,6 +2120,7 @@ class GenerateResultsReport(Wizard):
actual_report = ResultsReport.search([
('party', '=', reports['party']),
('entry', '=', reports['entry']),
('notebook', '=', reports['notebook']),
('report_grouper', '=', reports['report_grouper']),
('generation_type', '=', reports['generation_type']),
@ -2191,6 +2243,425 @@ class OpenSamplesPendingReporting(Wizard):
return 'end'
class GenerateReportStart(ModelView):
'Generate Results Report'
__name__ = 'lims.notebook.generate_results_report.start'
notebooks = fields.One2Many('lims.notebook', None, 'Samples',
readonly=True)
report = fields.Many2One('lims.results_report', 'Target Report',
states={'readonly': Bool(Eval('report_readonly'))},
domain=[('id', 'in', Eval('report_domain'))],
depends=['report_readonly', 'report_domain'])
report_readonly = fields.Boolean('Target Report readonly')
report_domain = fields.One2Many('lims.results_report', None,
'Target Report domain')
type = fields.Selection([
('preliminary', 'Preliminary'),
('final', 'Final'),
('complementary', 'Complementary'),
('corrective', 'Corrective'),
], 'Type', states={'readonly': True})
preliminary = fields.Boolean('Preliminary')
corrective = fields.Boolean('Corrective',
states={'readonly': ~Eval('type').in_(
['complementary', 'corrective'])},
depends=['type'])
reports_created = fields.One2Many('lims.results_report.version.detail',
None, 'Reports created')
@fields.depends('report', 'preliminary', 'corrective')
def on_change_with_type(self, name=None):
if self.preliminary:
return 'preliminary'
report_state = self._get_report_state()
if report_state == 'draft':
return 'final'
if self.corrective:
return 'corrective'
return 'complementary'
def _get_report_state(self):
ResultsDetail = Pool().get('lims.results_report.version.detail')
if not self.report:
return 'draft'
report_id = self.report.id
laboratory_id = Transaction().context.get(
'samples_pending_reporting_laboratory', None)
if not laboratory_id:
return 'draft'
last_detail = ResultsDetail.search([
('report_version.results_report', '=', report_id),
('report_version.laboratory', '=', laboratory_id),
], order=[('id', 'DESC')], limit=1)
if last_detail:
return last_detail[0].state
return 'draft'
class GenerateReport(Wizard):
'Generate Results Report'
__name__ = 'lims.notebook.generate_results_report'
start = StateView('lims.notebook.generate_results_report.start',
'lims.notebook_generate_results_report_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Generate', 'generate', 'tryton-ok', default=True),
])
generate = StateTransition()
open_ = StateAction('lims.act_lims_results_report_version_detail')
def default_start(self, fields):
pool = Pool()
Notebook = pool.get('lims.notebook')
ResultsReport = pool.get('lims.results_report')
ResultsDetail = pool.get('lims.results_report.version.detail')
res = {
'notebooks': [],
'report_readonly': False,
'report_domain': [],
'type': 'final',
'preliminary': False,
'corrective': False,
}
party = None
report_grouper = None
cie_fraction_type = None
for notebook in Notebook.browse(Transaction().context['active_ids']):
res['notebooks'].append(notebook.id)
if not res['report_readonly']:
if not party:
party = notebook.party.id
elif party != notebook.party.id:
res['report_readonly'] = True
for line in notebook.lines:
if not report_grouper:
report_grouper = line.analysis_detail.report_grouper
elif report_grouper != line.analysis_detail.report_grouper:
res['report_readonly'] = True
break
if cie_fraction_type is None:
cie_fraction_type = notebook.fraction.cie_fraction_type
elif cie_fraction_type != notebook.fraction.cie_fraction_type:
res['report_readonly'] = True
if notebook.state != 'complete':
res['preliminary'] = True
res['type'] = 'preliminary'
if not res['report_readonly']:
if res['preliminary']:
laboratory_id = Transaction().context.get(
'samples_pending_reporting_laboratory', None)
last_detail = ResultsDetail.search([
('party', '=', party),
('laboratory', '=', laboratory_id),
], order=[('id', 'DESC')], limit=1)
if last_detail and last_detail[0].state == 'preliminary':
res['report_domain'] = [
last_detail[0].report_version.results_report.id]
else:
reports = ResultsReport.search([
('party', '=', party),
('report_grouper', '=', report_grouper),
('cie_fraction_type', '=', cie_fraction_type),
])
if reports:
res['report_domain'] = [r.id for r in reports]
return res
def transition_generate(self):
pool = Pool()
Laboratory = pool.get('lims.laboratory')
ResultsVersion = pool.get('lims.results_report.version')
ResultsDetail = pool.get('lims.results_report.version.detail')
ResultsSample = pool.get('lims.results_report.version.detail.sample')
laboratory_id = Transaction().context.get(
'samples_pending_reporting_laboratory', None)
signer = Laboratory(laboratory_id).default_signer.id
reports_created = []
state = ('in_progress' if self.start.type == 'preliminary' else
'complete')
if self.start.report: # Result report selected
samples = []
for notebook in self.start.notebooks:
lines = self._get_notebook_lines(notebook.id, laboratory_id,
state)
notebook_lines = [{'notebook_line': line.id} for line in lines]
samples.append({
'notebook': notebook.id,
'notebook_lines': [('create', notebook_lines)],
})
details = {
'report_type_forced': 'polisample',
'type': self.start.type,
'signer': signer,
'samples': [('create', samples)],
}
actual_version = ResultsVersion.search([
('results_report', '=', self.start.report.id),
('laboratory', '=', laboratory_id),
], limit=1)
if not actual_version:
version, = ResultsVersion.create([{
'results_report': self.start.report.id,
'laboratory': laboratory_id,
'details': [('create', [details])],
}])
reports_details = [d.id for d in version.details]
else:
actual_version = actual_version[0]
draft_detail = ResultsDetail.search([
('report_version', '=', actual_version.id),
('state', '=', 'draft'),
], limit=1)
if not draft_detail:
details['report_version'] = actual_version.id
valid_detail = ResultsDetail.search([
('report_version', '=', actual_version.id),
('valid', '=', True),
], limit=1)
if valid_detail:
valid_detail = valid_detail[0]
details.update(ResultsDetail._get_detail_copy(
valid_detail))
detail, = ResultsDetail.create([details])
reports_details = [detail.id]
else:
draft_detail = draft_detail[0]
for sample in samples:
existing_sample = ResultsSample.search([
('version_detail', '=', draft_detail.id),
('notebook', '=', sample['notebook']),
], limit=1)
if not existing_sample:
sample['version_detail'] = draft_detail.id
ResultsSample.create([sample])
else:
del sample['notebook']
ResultsSample.write(existing_sample, sample)
del details['type']
del details['signer']
del details['samples']
ResultsDetail.write([draft_detail], details)
reports_details = [draft_detail.id]
reports_created.extend(reports_details)
else: # Not Result report selected
parties = {}
for notebook in self.start.notebooks:
key = (notebook.party.id, notebook.fraction.cie_fraction_type)
if key not in parties:
parties[key] = {
'party': notebook.party.id,
'entry': notebook.fraction.entry.id,
'cie_fraction_type': (
notebook.fraction.cie_fraction_type),
'english_report': (
notebook.fraction.entry.english_report),
'lines': [],
}
lines = self._get_notebook_lines(notebook.id, laboratory_id,
state)
parties[key]['lines'].extend(lines)
reports_details = []
for party in parties.values():
grouped_reports = {}
for line in party['lines']:
report_grouper = line.analysis_detail.report_grouper
if report_grouper not in grouped_reports:
grouped_reports[report_grouper] = []
grouped_reports[report_grouper].append(line)
for grouper, nlines in grouped_reports.items():
notebooks = {}
for line in nlines:
if line.notebook.id not in notebooks:
notebooks[line.notebook.id] = {
'notebook': line.notebook.id,
'lines': [],
}
notebooks[line.notebook.id]['lines'].append(line)
samples = []
for notebook in notebooks.values():
notebook_lines = [{'notebook_line': line.id}
for line in notebook['lines']]
samples.append({
'notebook': notebook['notebook'],
'notebook_lines': [('create', notebook_lines)],
})
details = {
'report_type_forced': 'polisample',
'type': self.start.type,
'signer': signer,
'samples': [('create', samples)],
}
versions = {
'laboratory': laboratory_id,
'details': [('create', [details])],
}
reports = {
'party': party['party'],
'entry': party['entry'],
'notebook': None,
'report_grouper': grouper,
'cie_fraction_type': party['cie_fraction_type'],
'english_report': party['english_report'],
'versions': [('create', [versions])],
}
report_detail = self._get_results_report(laboratory_id,
reports, versions, details, samples)
reports_details.extend(report_detail)
reports_created.extend(reports_details)
self.start.reports_created = reports_created
return 'open_'
def _get_notebook_lines(self, notebook_id, laboratory_id, state):
cursor = Transaction().connection.cursor()
pool = Pool()
ResultsLine = pool.get('lims.results_report.version.detail.line')
NotebookLine = pool.get('lims.notebook.line')
EntryDetailAnalysis = pool.get('lims.entry.detail.analysis')
Notebook = pool.get('lims.notebook')
draft_lines_ids = []
draft_lines = ResultsLine.search([
('detail_sample.notebook', '=', notebook_id),
('detail_sample.version_detail.laboratory', '=', laboratory_id),
('detail_sample.version_detail.state', 'in', ['draft', 'revised']),
('detail_sample.version_detail.type', '!=', 'preliminary'),
])
if draft_lines:
draft_lines_ids = [dl.notebook_line.id for dl in draft_lines]
clause = [
('notebook', '=', notebook_id),
('laboratory', '=', laboratory_id),
('notebook.fraction.type.report', '=', True),
('report', '=', True),
('annulled', '=', False),
('results_report', '=', None),
('id', 'not in', draft_lines_ids),
]
if state == 'in_progress':
clause.extend(Notebook._get_samples_in_progress_clause())
else:
clause.append(('accepted', '=', True))
excluded_notebooks = Notebook._get_excluded_notebooks(
[notebook_id], laboratory_id)
if excluded_notebooks:
for n_id, grouper in excluded_notebooks:
cursor.execute('SELECT nl.id '
'FROM "' + NotebookLine._table + '" nl '
'INNER JOIN "' + EntryDetailAnalysis._table + '" d '
'ON d.id = nl.analysis_detail '
'WHERE nl.notebook = %s AND d.report_grouper = %s',
(n_id, grouper))
excluded_notebook_lines = [x[0] for x in cursor.fetchall()]
clause.append(('id', 'not in', excluded_notebook_lines))
return NotebookLine.search(clause)
def _get_results_report(self, laboratory_id, reports, versions, details,
samples, append=True):
pool = Pool()
ResultsReport = pool.get('lims.results_report')
ResultsVersion = pool.get('lims.results_report.version')
ResultsDetail = pool.get('lims.results_report.version.detail')
ResultsSample = pool.get('lims.results_report.version.detail.sample')
if not append:
report, = ResultsReport.create([reports])
reports_details = [d.id for d in report.versions[0].details]
return reports_details
actual_report = ResultsReport.search([
('party', '=', reports['party']),
('entry', '=', reports['entry']),
('report_grouper', '=', reports['report_grouper']),
('cie_fraction_type', '=', reports['cie_fraction_type']),
], limit=1)
if not actual_report:
report, = ResultsReport.create([reports])
reports_details = [d.id for d in report.versions[0].details]
return reports_details
actual_report = actual_report[0]
actual_version = ResultsVersion.search([
('results_report', '=', actual_report.id),
('laboratory', '=', laboratory_id),
], limit=1)
if not actual_version:
version, = ResultsVersion.create([{
'results_report': actual_report.id,
'laboratory': laboratory_id,
'details': [('create', [details])],
}])
reports_details = [d.id for d in version.details]
return reports_details
actual_version = actual_version[0]
draft_detail = ResultsDetail.search([
('report_version', '=', actual_version.id),
('state', '=', 'draft'),
], limit=1)
if not draft_detail:
details['report_version'] = actual_version.id
valid_detail = ResultsDetail.search([
('report_version', '=', actual_version.id),
('valid', '=', True),
], limit=1)
if valid_detail:
valid_detail = valid_detail[0]
details.update(ResultsDetail._get_detail_copy(valid_detail))
detail, = ResultsDetail.create([details])
reports_details = [detail.id]
return reports_details
draft_detail = draft_detail[0]
for sample in samples:
existing_sample = ResultsSample.search([
('version_detail', '=', draft_detail.id),
('notebook', '=', sample['notebook']),
], limit=1)
if not existing_sample:
sample['version_detail'] = draft_detail.id
ResultsSample.create([sample])
else:
del sample['notebook']
ResultsSample.write(existing_sample, sample)
reports_details = [draft_detail.id]
return reports_details
def do_open_(self, action):
action['pyson_domain'] = PYSONEncoder().encode([
('id', 'in', [r.id for r in self.start.reports_created]),
])
self.start.reports_created = None
return action, {}
def transition_open_(self):
return 'end'
def end(self):
return 'reload'
class PrintResultsReport(Wizard):
'Print Results Report'
__name__ = 'lims.print_results_report'

View File

@ -285,6 +285,24 @@
<field name="wiz_name">lims.samples_pending_reporting</field>
</record>
<!-- Wizard Generate Results Report -->
<record model="ir.ui.view" id="notebook_generate_results_report_view_form">
<field name="model">lims.notebook.generate_results_report.start</field>
<field name="type">form</field>
<field name="name">notebook_generate_results_report_form</field>
</record>
<record model="ir.action.wizard" id="wiz_notebook_generate_results_report">
<field name="name">Generate Results Report</field>
<field name="wiz_name">lims.notebook.generate_results_report</field>
</record>
<record model="ir.action.keyword" id="wiz_notebook_generate_results_report_keyword">
<field name="keyword">form_action</field>
<field name="model">lims.notebook,-2</field>
<field name="action" ref="wiz_notebook_generate_results_report"/>
</record>
<!-- Wizard Generate Results Reports -->
<record model="ir.ui.view" id="lims_generate_results_report_start_view_form">

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<form>
<label name="report"/>
<field name="report"/>
<group id="type" colspan="2" col="4">
<label name="type"/>
<field name="type"/>
<label name="corrective"/>
<field name="corrective" xexpand="0"/>
</group>
<field name="notebooks" colspan="4" mode="tree,form"
view_ids="lims.lims_samples_pending_reporting_view_list,lims.lims_samples_pending_reporting_view_form"/>
<group id="invisible" colspan="4" col="1">
<field name="report_readonly" invisible="1"/>
<field name="report_domain" invisible="1"/>
<field name="preliminary" invisible="1"/>
</group>
</form>

View File

@ -56,6 +56,16 @@ class ResultsReportVersionDetail(metaclass=PoolMeta):
for sample in self.samples:
sample.diagnosis = content
@classmethod
def _get_detail_copy(cls, detail):
detail_default = super(ResultsReportVersionDetail,
cls)._get_detail_copy(detail)
if detail.diagnostician:
detail_default['diagnostician'] = detail.diagnostician.id
if detail.diagnosis_template:
detail_default['diagnosis_template'] = detail.diagnosis_template.id
return detail_default
class ResultsReportVersionDetailSample(metaclass=PoolMeta):
__name__ = 'lims.results_report.version.detail.sample'
@ -78,6 +88,14 @@ class ResultsReportVersionDetailSample(metaclass=PoolMeta):
self.version_detail.diagnosis_template.diagnosis_states]
return []
@classmethod
def _get_sample_copy(cls, sample):
sample_default = super(ResultsReportVersionDetailSample,
cls)._get_sample_copy(sample)
sample_default['diagnosis'] = sample.diagnosis
sample_default['diagnosis_states'] = sample.diagnosis_states
return sample_default
class ResultReport(metaclass=PoolMeta):
__name__ = 'lims.result_report'

View File

@ -30,6 +30,18 @@ class ResultsReportVersionDetailSample(metaclass=PoolMeta):
domain=[('component', '=', Eval('component'))],
depends=['component'])
@classmethod
def _get_sample_copy(cls, sample):
sample_default = super(ResultsReportVersionDetailSample,
cls)._get_sample_copy(sample)
sample_default['precedent1'] = (sample.precedent1 and
sample.precedent1 or None)
sample_default['precedent2'] = (sample.precedent2 and
sample.precedent2 or None)
sample_default['precedent3'] = (sample.precedent3 and
sample.precedent3 or None)
return sample_default
class ResultsReportVersionDetailLine(metaclass=PoolMeta):
__name__ = 'lims.results_report.version.detail.line'
@ -91,6 +103,7 @@ class ResultsReportVersionDetailLine(metaclass=PoolMeta):
res = round(float(result), decimals)
if decimals == 0:
res = int(res)
res = str(res)
else:
res = ''

View File

@ -1137,6 +1137,8 @@
{% endif %} <!-- END POLISAMPLE -->
<br/><br/>
{% endfor %}
</td>
</tr>

View File

@ -29,6 +29,14 @@ class ResultsReportVersionDetail(metaclass=PoolMeta):
if 'required' in cls.resultrange_origin.states:
del cls.resultrange_origin.states['required']
@classmethod
def _get_detail_copy(cls, detail):
detail_default = super(ResultsReportVersionDetail,
cls)._get_detail_copy(detail)
if detail.template:
detail_default['template'] = detail.template.id
return detail_default
class ResultReport(metaclass=PoolMeta):
__name__ = 'lims.result_report'