From 384bd567ae623a1470daac488272f70380cf8fd1 Mon Sep 17 00:00:00 2001 From: lwark Date: Thu, 20 Jun 2024 13:31:36 -0500 Subject: [PATCH] New docx templates --- .../backend/db/models/submissions.py | 30 ++++++- src/submissions/backend/excel/writer.py | 73 +++++++++++++++--- src/submissions/backend/validators/pydant.py | 26 +++---- .../frontend/widgets/equipment_usage.py | 4 +- .../frontend/widgets/submission_details.py | 57 ++++++++------ .../frontend/widgets/submission_widget.py | 1 + .../bacterialculture_subdocument.docx | Bin 0 -> 13016 bytes .../templates/basicsubmission_details.html | 33 +------- .../templates/basicsubmission_document.docx | Bin 0 -> 14385 bytes src/submissions/templates/css/styles.css | 29 +++++++ .../templates/wastewater_subdocument.docx | Bin 0 -> 13602 bytes src/submissions/tools.py | 2 + 12 files changed, 175 insertions(+), 80 deletions(-) create mode 100644 src/submissions/templates/bacterialculture_subdocument.docx create mode 100644 src/submissions/templates/basicsubmission_document.docx create mode 100644 src/submissions/templates/css/styles.css create mode 100644 src/submissions/templates/wastewater_subdocument.docx diff --git a/src/submissions/backend/db/models/submissions.py b/src/submissions/backend/db/models/submissions.py index 3419f28..6a0d6f1 100644 --- a/src/submissions/backend/db/models/submissions.py +++ b/src/submissions/backend/db/models/submissions.py @@ -4,6 +4,7 @@ Models for the main submission and sample types. from __future__ import annotations import sys +from copy import deepcopy from getpass import getuser import logging, uuid, tempfile, re, yaml, base64 from zipfile import ZipFile @@ -728,6 +729,11 @@ class BasicSubmission(BaseClass): logger.info(f"Hello from {cls.__mapper_args__['polymorphic_identity']} autofill") return input_excel + @classmethod + def custom_docx_writer(cls, input_dict): + + return input_dict + @classmethod def enforce_name(cls, instr: str, data: dict | None = {}) -> str: """ @@ -1439,7 +1445,7 @@ class Wastewater(BasicSubmission): dummy_samples = [] for item in input_dict['samples']: # logger.debug(f"Sample dict: {item}") - thing = item + thing = deepcopy(item) try: thing['row'] = thing['source_row'] thing['column'] = thing['source_column'] @@ -1486,6 +1492,28 @@ class Wastewater(BasicSubmission): self.update_subsampassoc(sample=sample, input_dict=sample_dict) # self.report.add_result(Result(msg=f"We added PCR info to {sub.rsl_plate_num}.", status='Information')) + @classmethod + def custom_docx_writer(cls, input_dict): + from backend.excel.writer import DocxWriter + input_dict = super().custom_docx_writer(input_dict) + well_24 = [] + samples_copy = deepcopy(input_dict['samples']) + for sample in sorted(samples_copy, key=itemgetter('column', 'row')): + # for sample in input_dict['samples']: + try: + row = sample['source_row'] + except KeyError: + continue + try: + column = sample['source_column'] + except KeyError: + continue + copy = dict(submitter_id=sample['submitter_id'], row=row, column=column) + well_24.append(copy) + input_dict['origin_plate'] = DocxWriter.create_plate_map(sample_list=well_24, rows=4, columns=6) + return input_dict + + class WastewaterArtic(BasicSubmission): """ diff --git a/src/submissions/backend/excel/writer.py b/src/submissions/backend/excel/writer.py index 8bbe4ec..d65ad40 100644 --- a/src/submissions/backend/excel/writer.py +++ b/src/submissions/backend/excel/writer.py @@ -1,10 +1,11 @@ import logging from copy import copy +from operator import itemgetter from pathlib import Path # from pathlib import Path from pprint import pformat from typing import List - +from collections import OrderedDict from jinja2 import TemplateNotFound from openpyxl import load_workbook, Workbook from backend.db.models import SubmissionType, KitType, BasicSubmission @@ -13,6 +14,7 @@ from io import BytesIO from collections import OrderedDict from tools import jinja_template_loading from docxtpl import DocxTemplate +from docx import Document logger = logging.getLogger(f"submissions.{__name__}") @@ -460,14 +462,65 @@ class TipWriter(object): class DocxWriter(object): def __init__(self, base_dict: dict): + self.sub_obj = BasicSubmission.find_polymorphic_subclass(polymorphic_identity=base_dict['submission_type']) env = jinja_template_loading() - temp_name = f"{base_dict['submission_type'].replace(' ', '').lower()}_document.docx" - path = Path(env.loader.__getattribute__("searchpath")[0]).joinpath(temp_name) - template = DocxTemplate(path) + temp_name = f"{base_dict['submission_type'].replace(' ', '').lower()}_subdocument.docx" + path = Path(env.loader.__getattribute__("searchpath")[0]) + main_template = path.joinpath("basicsubmission_document.docx") + subdocument = path.joinpath(temp_name) + if subdocument.exists(): + main_template = self.create_merged_template(main_template, subdocument) + self.template = DocxTemplate(main_template) + base_dict['platemap'] = self.create_plate_map(base_dict['samples'], rows=8, columns=12) + # logger.debug(pformat(base_dict['plate_map'])) try: - template.render(base_dict) - except FileNotFoundError: - template = DocxTemplate( - Path(env.loader.__getattribute__("searchpath")[0]).joinpath("basicsubmission_document.docx")) - template.render({"sub": base_dict}) - template.save("test.docx") + base_dict['excluded'] += ["platemap"] + except KeyError: + base_dict['excluded'] = ["platemap"] + base_dict = self.sub_obj.custom_docx_writer(base_dict) + # logger.debug(f"Base dict: {pformat(base_dict)}") + self.template.render({"sub": base_dict}) + + @classmethod + def create_plate_map(self, sample_list: List[dict], rows: int = 0, columns: int = 0) -> List[list]: + sample_list = sorted(sample_list, key=itemgetter('column', 'row')) + if rows == 0: + rows = max([sample['row'] for sample in sample_list]) + if columns == 0: + columns = max([sample['column'] for sample in sample_list]) + output = [] + for row in range(0, rows): + contents = [''] * columns + for column in range(0, columns): + try: + ooi = [item for item in sample_list if item['row']==row+1 and item['column']==column+1][0] + except IndexError: + continue + contents[column] = ooi['submitter_id'] + # contents = [sample['submitter_id'] for sample in sample_list if sample['row'] == row + 1] + # contents = [f"{sample['row']},{sample['column']}" for sample in sample_list if sample['row'] == row + 1] + if len(contents) < columns: + contents += [''] * (columns - len(contents)) + if not contents: + contents = [''] * columns + output.append(contents) + return output + + def create_merged_template(self, *args): + merged_document = Document() + output = BytesIO() + for index, file in enumerate(args): + sub_doc = Document(file) + # Don't add a page break if you've reached the last file. + # if index < len(args) - 1: + # sub_doc.add_page_break() + for element in sub_doc.element.body: + merged_document.element.body.append(element) + merged_document.save(output) + return output + + + def save(self, filename: Path | str): + if isinstance(filename, str): + filename = Path(filename) + self.template.save(filename) diff --git a/src/submissions/backend/validators/pydant.py b/src/submissions/backend/validators/pydant.py index 2ef4951..2a30cce 100644 --- a/src/submissions/backend/validators/pydant.py +++ b/src/submissions/backend/validators/pydant.py @@ -327,17 +327,17 @@ class PydEquipment(BaseModel, extra='ignore'): process = Process.query(name=self.processes[0]) if process is None: logger.error(f"Found unknown process: {process}.") - from frontend.widgets.pop_ups import QuestionAsker - dlg = QuestionAsker(title="Add Process?", - message=f"Unable to find {self.processes[0]} in the database.\nWould you like to add it?") - if dlg.exec(): - kit = submission.extraction_kit - submission_type = submission.submission_type - process = Process(name=self.processes[0]) - process.kit_types.append(kit) - process.submission_types.append(submission_type) - process.equipment.append(equipment) - process.save() + # from frontend.widgets.pop_ups import QuestionAsker + # dlg = QuestionAsker(title="Add Process?", + # message=f"Unable to find {self.processes[0]} in the database.\nWould you like to add it?") + # if dlg.exec(): + # kit = submission.extraction_kit + # submission_type = submission.submission_type + # process = Process(name=self.processes[0]) + # process.kit_types.append(kit) + # process.submission_types.append(submission_type) + # process.equipment.append(equipment) + # process.save() assoc.process = process assoc.role = self.role else: @@ -727,7 +727,7 @@ class PydSubmission(BaseModel, extra='allow'): if equip is None: continue equip, association = equip.toSQL(submission=instance) - if association is not None: + if association is not None and association not in instance.submission_equipment_associations: # association.save() # logger.debug( # f"Equipment association SQL object to be added to submission: {association.__dict__}") @@ -738,7 +738,7 @@ class PydSubmission(BaseModel, extra='allow'): continue logger.debug(f"Converting tips: {tips} to sql.") association = tips.to_sql(submission=instance) - if association is not None: + if association is not None and association not in instance.submission_tips_associations: # association.save() instance.submission_tips_associations.append(association) case item if item in instance.jsons(): diff --git a/src/submissions/frontend/widgets/equipment_usage.py b/src/submissions/frontend/widgets/equipment_usage.py index 3570cf2..8af2167 100644 --- a/src/submissions/frontend/widgets/equipment_usage.py +++ b/src/submissions/frontend/widgets/equipment_usage.py @@ -59,7 +59,7 @@ class EquipmentUsage(QDialog): case _: pass logger.debug(f"parsed output of Equsage form: {pformat(output)}") - return [item for item in output if item is not None] + return [item.strip() for item in output if item is not None] class LabelRow(QWidget): @@ -165,7 +165,7 @@ class RoleComboBox(QWidget): try: return PydEquipment( name=eq.name, - processes=[self.process.currentText()], + processes=[self.process.currentText().strip()], role=self.role.name, asset_number=eq.asset_number, nickname=eq.nickname, diff --git a/src/submissions/frontend/widgets/submission_details.py b/src/submissions/frontend/widgets/submission_details.py index b313810..911d76f 100644 --- a/src/submissions/frontend/widgets/submission_details.py +++ b/src/submissions/frontend/widgets/submission_details.py @@ -1,3 +1,5 @@ +from PyQt6.QtGui import QPageSize +from PyQt6.QtPrintSupport import QPrinter from PyQt6.QtWidgets import (QDialog, QPushButton, QVBoxLayout, QMessageBox, QDialogButtonBox, QTextEdit) from PyQt6.QtWebEngineWidgets import QWebEngineView @@ -17,6 +19,8 @@ from pprint import pformat from html2image import Html2Image from PIL import Image from typing import List +from backend.excel.writer import DocxWriter + logger = logging.getLogger(f"submissions.{__name__}") @@ -90,13 +94,17 @@ class SubmissionDetails(QDialog): # del self.base_dict['id'] # logger.debug(f"Creating barcode.") # logger.debug(f"Making platemap...") + self.base_dict['platemap'] = BasicSubmission.make_plate_map(sample_list=submission.hitpick_plate()) self.base_dict, self.template = submission.get_details_template(base_dict=self.base_dict) + template_path = Path(self.template.environment.loader.__getattribute__("searchpath")[0]) + with open(template_path.joinpath("css", "styles.css"), "r") as f: + css = f.read() logger.debug(f"Submission_details: {pformat(self.base_dict)}") - self.html = self.template.render(sub=self.base_dict, signing_permission=is_power_user()) + self.html = self.template.render(sub=self.base_dict, signing_permission=is_power_user(), css=css) self.webview.setHtml(self.html) - # with open("test.html", "w") as f: - # f.write(self.html) + with open("test.html", "w") as f: + f.write(self.html) self.setWindowTitle(f"Submission Details - {submission.rsl_plate_num}") @pyqtSlot(str) @@ -112,31 +120,32 @@ class SubmissionDetails(QDialog): """ Renders submission to html, then creates and saves .pdf file to user selected file. """ - logger.debug(f"Base dict: {pformat(self.base_dict)}") + writer = DocxWriter(base_dict=self.base_dict) fname = select_save_file(obj=self, default_name=self.base_dict['plate_number'], extension="docx") - image_io = BytesIO() - temp_dir = Path(TemporaryDirectory().name) - hti = Html2Image(output_path=temp_dir, size=(2400, 1500)) - temp_file = Path(TemporaryFile(dir=temp_dir, suffix=".png").name) - screenshot = hti.screenshot(self.base_dict['platemap'], save_as=temp_file.name) - export_map = Image.open(screenshot[0]) - export_map = export_map.convert('RGB') + writer.save(fname) + # image_io = BytesIO() + # temp_dir = Path(TemporaryDirectory().name) + # hti = Html2Image(output_path=temp_dir, size=(2400, 1500)) + # temp_file = Path(TemporaryFile(dir=temp_dir, suffix=".png").name) + # screenshot = hti.screenshot(self.base_dict['platemap'], save_as=temp_file.name) + # export_map = Image.open(screenshot[0]) + # export_map = export_map.convert('RGB') + # try: + # export_map.save(image_io, 'JPEG') + # except AttributeError: + # logger.error(f"No plate map found") + # self.base_dict['export_map'] = base64.b64encode(image_io.getvalue()).decode('utf-8') + # del self.base_dict['platemap'] + # self.html2 = self.template.render(sub=self.base_dict) try: - export_map.save(image_io, 'JPEG') - except AttributeError: - logger.error(f"No plate map found") - self.base_dict['export_map'] = base64.b64encode(image_io.getvalue()).decode('utf-8') - del self.base_dict['platemap'] - self.html2 = self.template.render(sub=self.base_dict) - try: - html_to_pdf(html=self.html2, output_file=fname) + html_to_pdf(html=self.html, output_file=fname) except PermissionError as e: logger.error(f"Error saving pdf: {e}") - msg = QMessageBox() - msg.setText("Permission Error") - msg.setInformativeText(f"Looks like {fname.__str__()} is open.\nPlease close it and try again.") - msg.setWindowTitle("Permission Error") - msg.exec() + # msg = QMessageBox() + # msg.setText("Permission Error") + # msg.setInformativeText(f"Looks like {fname.__str__()} is open.\nPlease close it and try again.") + # msg.setWindowTitle("Permission Error") + # msg.exec() class SubmissionComment(QDialog): diff --git a/src/submissions/frontend/widgets/submission_widget.py b/src/submissions/frontend/widgets/submission_widget.py index 9055571..d66433d 100644 --- a/src/submissions/frontend/widgets/submission_widget.py +++ b/src/submissions/frontend/widgets/submission_widget.py @@ -312,6 +312,7 @@ class SubmissionFormWidget(QWidget): if dlg.exec(): # NOTE: Do not add duplicate reagents. result = None + else: self.app.ctx.database_session.rollback() report.add_result(Result(msg="Overwrite cancelled", status="Information")) diff --git a/src/submissions/templates/bacterialculture_subdocument.docx b/src/submissions/templates/bacterialculture_subdocument.docx new file mode 100644 index 0000000000000000000000000000000000000000..03e7ca2752385da3ce482beeec68200d9f2e2357 GIT binary patch literal 13016 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 literal 0 HcmV?d00001 diff --git a/src/submissions/templates/basicsubmission_details.html b/src/submissions/templates/basicsubmission_details.html index 23c31e7..8dbf00c 100644 --- a/src/submissions/templates/basicsubmission_details.html +++ b/src/submissions/templates/basicsubmission_details.html @@ -2,38 +2,11 @@ {% block head %} + {% if css %} + {% endif %} Submission Details for {{ sub['Plate Number'] }} {% endblock %} diff --git a/src/submissions/templates/basicsubmission_document.docx b/src/submissions/templates/basicsubmission_document.docx new file mode 100644 index 0000000000000000000000000000000000000000..5e9bd491b0c2ec21bfaeb55cca42217e9e84e84b GIT binary patch literal 14385 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 literal 0 HcmV?d00001 diff --git a/src/submissions/tools.py b/src/submissions/tools.py index aec3c4c..05aeb03 100644 --- a/src/submissions/tools.py +++ b/src/submissions/tools.py @@ -658,11 +658,13 @@ def html_to_pdf(html, output_file: Path | str): logger.debug(f"Printing PDF to {output_file}") document = QWebEngineView() document.setHtml(html) + # document.show() printer = QPrinter(QPrinter.PrinterMode.HighResolution) printer.setOutputFormat(QPrinter.OutputFormat.PdfFormat) printer.setOutputFileName(output_file.absolute().__str__()) printer.setPageSize(QPageSize(QPageSize.PageSizeId.A4)) document.print(printer) + # document.close() # HTML(string=html).write_pdf(output_file) # new_parser = HtmlToDocx() # docx = new_parser.parse_html_string(html)