Added report tab with HTML and excel export.

This commit is contained in:
lwark
2024-10-04 11:30:22 -05:00
parent c5470b9062
commit c89ec2b62c
12 changed files with 295 additions and 181 deletions

View File

@@ -24,6 +24,7 @@ from .controls_chart import ControlsViewer
from .kit_creator import KitAdder
from .submission_type_creator import SubmissionTypeAdder, SubmissionType
from .sample_search import SearchBox
from .summary import Summary
logger = logging.getLogger(f'submissions.{__name__}')
logger.info("Hello, I am a logger")
@@ -69,7 +70,7 @@ class App(QMainWindow):
fileMenu = menuBar.addMenu("&File")
# NOTE: Creating menus using a title
methodsMenu = menuBar.addMenu("&Methods")
reportMenu = menuBar.addMenu("&Reports")
# reportMenu = menuBar.addMenu("&Reports")
maintenanceMenu = menuBar.addMenu("&Monthly")
helpMenu = menuBar.addMenu("&Help")
helpMenu.addAction(self.helpAction)
@@ -80,7 +81,7 @@ class App(QMainWindow):
fileMenu.addAction(self.yamlImportAction)
methodsMenu.addAction(self.searchLog)
methodsMenu.addAction(self.searchSample)
reportMenu.addAction(self.generateReportAction)
# reportMenu.addAction(self.generateReportAction)
maintenanceMenu.addAction(self.joinExtractionAction)
maintenanceMenu.addAction(self.joinPCRAction)
@@ -102,7 +103,7 @@ class App(QMainWindow):
# logger.debug(f"Creating actions...")
self.importAction = QAction("&Import Submission", self)
self.addReagentAction = QAction("Add Reagent", self)
self.generateReportAction = QAction("Make Report", self)
# self.generateReportAction = QAction("Make Report", self)
self.addKitAction = QAction("Import Kit", self)
self.addOrgAction = QAction("Import Org", self)
self.joinExtractionAction = QAction("Link Extraction Logs")
@@ -122,7 +123,7 @@ class App(QMainWindow):
# logger.debug(f"Connecting actions...")
self.importAction.triggered.connect(self.table_widget.formwidget.importSubmission)
self.addReagentAction.triggered.connect(self.table_widget.formwidget.add_reagent)
self.generateReportAction.triggered.connect(self.table_widget.sub_wid.generate_report)
# self.generateReportAction.triggered.connect(self.table_widget.sub_wid.generate_report)
self.joinExtractionAction.triggered.connect(self.table_widget.sub_wid.link_extractions)
self.joinPCRAction.triggered.connect(self.table_widget.sub_wid.link_pcr)
self.helpAction.triggered.connect(self.showAbout)
@@ -254,8 +255,8 @@ class AddSubForm(QWidget):
# NOTE: Add tabs
self.tabs.addTab(self.tab1,"Submissions")
self.tabs.addTab(self.tab2,"Controls")
self.tabs.addTab(self.tab3, "Add SubmissionType")
self.tabs.addTab(self.tab4, "Add Kit")
self.tabs.addTab(self.tab3, "Summary Report")
# self.tabs.addTab(self.tab4, "Add Kit")
# NOTE: Create submission adder form
self.formwidget = SubmissionFormContainer(self)
self.formlayout = QVBoxLayout(self)
@@ -282,14 +283,15 @@ class AddSubForm(QWidget):
self.tab2.layout.addWidget(self.controls_viewer)
self.tab2.setLayout(self.tab2.layout)
# NOTE: create custom widget to add new tabs
ST_adder = SubmissionTypeAdder(self)
# ST_adder = SubmissionTypeAdder(self)
summary_report = Summary(self)
self.tab3.layout = QVBoxLayout(self)
self.tab3.layout.addWidget(ST_adder)
self.tab3.layout.addWidget(summary_report)
self.tab3.setLayout(self.tab3.layout)
kit_adder = KitAdder(self)
self.tab4.layout = QVBoxLayout(self)
self.tab4.layout.addWidget(kit_adder)
self.tab4.setLayout(self.tab4.layout)
# kit_adder = KitAdder(self)
# self.tab4.layout = QVBoxLayout(self)
# self.tab4.layout.addWidget(kit_adder)
# self.tab4.setLayout(self.tab4.layout)
# NOTE: add tabs to main widget
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)

View File

@@ -8,7 +8,7 @@ from typing import Tuple
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QComboBox, QHBoxLayout,
QDateEdit, QLabel, QSizePolicy, QPushButton
QDateEdit, QLabel, QSizePolicy, QPushButton, QGridLayout
)
from PyQt6.QtCore import QSignalBlocker
from backend.db import ControlType, Control
@@ -17,7 +17,7 @@ import logging
from pandas import DataFrame
from tools import Report, Result, get_unique_values_in_df_column, Settings, report_result
from frontend.visualizations.control_charts import CustomFigure
from .misc import StartEndDatePicker
logger = logging.getLogger(f"submissions.{__name__}")
@@ -28,10 +28,10 @@ class ControlsViewer(QWidget):
self.app = self.parent().parent()
# logger.debug(f"\n\n{self.app}\n\n")
self.report = Report()
self.datepicker = ControlsDatePicker()
self.datepicker = StartEndDatePicker(default_start=-180)
self.webengineview = QWebEngineView()
# NOTE: set tab2 layout
self.layout = QVBoxLayout(self)
self.layout = QGridLayout(self)
self.control_typer = QComboBox()
# NOTE: fetch types of controls
con_types = [item.name for item in ControlType.query()]
@@ -44,18 +44,20 @@ class ControlsViewer(QWidget):
self.sub_typer = QComboBox()
self.sub_typer.setEnabled(False)
# NOTE: add widgets to tab2 layout
self.layout.addWidget(self.datepicker)
self.layout.addWidget(self.control_typer)
self.layout.addWidget(self.mode_typer)
self.layout.addWidget(self.sub_typer)
self.layout.addWidget(self.webengineview)
self.layout.addWidget(self.datepicker, 0,0,1,2)
self.save_button = QPushButton("Save Chart", parent=self)
self.layout.addWidget(self.save_button, 0,2,1,1)
self.layout.addWidget(self.control_typer, 1,0,1,3)
self.layout.addWidget(self.mode_typer, 2,0,1,3)
self.layout.addWidget(self.sub_typer, 3,0,1,3)
self.layout.addWidget(self.webengineview, 4,0,1,3)
self.setLayout(self.layout)
self.controls_getter()
self.control_typer.currentIndexChanged.connect(self.controls_getter)
self.mode_typer.currentIndexChanged.connect(self.controls_getter)
self.datepicker.start_date.dateChanged.connect(self.controls_getter)
self.datepicker.end_date.dateChanged.connect(self.controls_getter)
self.datepicker.save_button.pressed.connect(self.save_chart_function)
self.save_button.pressed.connect(self.save_chart_function)
def save_chart_function(self):
self.fig.save_figure(parent=self)
@@ -141,7 +143,7 @@ class ControlsViewer(QWidget):
# NOTE: if no data found from query set fig to none for reporting in webview
if controls is None:
fig = None
self.datepicker.save_button.setEnabled(False)
self.save_button.setEnabled(False)
else:
# NOTE: change each control to list of dictionaries
data = [control.convert_by_mode(mode=self.mode) for control in controls]
@@ -160,7 +162,7 @@ class ControlsViewer(QWidget):
# NOTE: send dataframe to chart maker
df, modes = self.prep_df(ctx=self.app.ctx, df=df)
fig = CustomFigure(df=df, ytitle=title, modes=modes, parent=self)
self.datepicker.save_button.setEnabled(True)
self.save_button.setEnabled(True)
# logger.debug(f"Updating figure...")
self.fig = fig
# NOTE: construct html for webview
@@ -200,8 +202,6 @@ class ControlsViewer(QWidget):
continue
# NOTE: The actual percentage from kraken was off due to exclusion of NaN, recalculating.
df[column] = 100 * df[count_col] / df.groupby('name')[count_col].transform('sum')
logger.debug(df)
logger.debug(safe)
df = df[[c for c in df.columns if c in safe]]
# NOTE: move date of sample submitted on same date as previous ahead one.
df = self.displace_date(df=df)
@@ -340,28 +340,27 @@ class ControlsViewer(QWidget):
return df
class ControlsDatePicker(QWidget):
"""
custom widget to pick start and end dates for controls graphs
"""
def __init__(self) -> None:
super().__init__()
self.start_date = QDateEdit(calendarPopup=True)
# NOTE: start date is two months prior to end date by default
sixmonthsago = QDate.currentDate().addDays(-180)
self.start_date.setDate(sixmonthsago)
self.end_date = QDateEdit(calendarPopup=True)
self.end_date.setDate(QDate.currentDate())
self.layout = QHBoxLayout()
self.layout.addWidget(QLabel("Start Date"))
self.layout.addWidget(self.start_date)
self.layout.addWidget(QLabel("End Date"))
self.layout.addWidget(self.end_date)
self.setLayout(self.layout)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.save_button = QPushButton("Save Chart", parent=self)
self.layout.addWidget(self.save_button)
def sizeHint(self) -> QSize:
return QSize(80, 20)
# class ControlsDatePicker(QWidget):
# """
# custom widget to pick start and end dates for controls graphs
# """
#
# def __init__(self) -> None:
# super().__init__()
# self.start_date = QDateEdit(calendarPopup=True)
# # NOTE: start date is two months prior to end date by default
# sixmonthsago = QDate.currentDate().addDays(-180)
# self.start_date.setDate(sixmonthsago)
# self.end_date = QDateEdit(calendarPopup=True)
# self.end_date.setDate(QDate.currentDate())
# self.layout = QHBoxLayout()
# self.layout.addWidget(QLabel("Start Date"))
# self.layout.addWidget(self.start_date)
# self.layout.addWidget(QLabel("End Date"))
# self.layout.addWidget(self.end_date)
# self.setLayout(self.layout)
# self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
#
#
# def sizeHint(self) -> QSize:
# return QSize(80, 20)

View File

@@ -2,17 +2,20 @@
Contains miscellaneous widgets for frontend functions
'''
from datetime import date
from PyQt6.QtGui import QPageLayout, QPageSize, QStandardItem, QStandardItemModel
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWidgets import (
QLabel, QVBoxLayout,
QLineEdit, QComboBox, QDialog,
QDialogButtonBox, QDateEdit, QPushButton, QFormLayout
QLineEdit, QComboBox, QDialog,
QDialogButtonBox, QDateEdit, QPushButton, QFormLayout, QWidget, QHBoxLayout, QSizePolicy
)
from PyQt6.QtCore import Qt, QDate
from PyQt6.QtCore import Qt, QDate, QSize, QMarginsF, pyqtSlot, pyqtSignal, QEvent
from tools import jinja_template_loading
from backend.db.models import *
import logging
from .pop_ups import AlertPop
from .functions import select_open_file
from .functions import select_open_file, select_save_file
logger = logging.getLogger(f"submissions.{__name__}")
@@ -22,8 +25,10 @@ env = jinja_template_loading()
class AddReagentForm(QDialog):
"""
dialog to add gather info about new reagent
"""
def __init__(self, reagent_lot:str|None=None, reagent_role: str | None=None, expiry: date | None=None, reagent_name: str | None=None) -> None:
"""
def __init__(self, reagent_lot: str | None = None, reagent_role: str | None = None, expiry: date | None = None,
reagent_name: str | None = None) -> None:
super().__init__()
if reagent_lot is None:
reagent_lot = reagent_role
@@ -71,7 +76,8 @@ class AddReagentForm(QDialog):
self.layout.addWidget(self.name_input)
self.layout.addWidget(QLabel("Lot:"))
self.layout.addWidget(self.lot_input)
self.layout.addWidget(QLabel("Expiry:\n(use exact date on reagent.\nEOL will be calculated from kit automatically)"))
self.layout.addWidget(
QLabel("Expiry:\n(use exact date on reagent.\nEOL will be calculated from kit automatically)"))
self.layout.addWidget(self.exp_input)
self.layout.addWidget(QLabel("Type:"))
self.layout.addWidget(self.type_input)
@@ -85,57 +91,57 @@ class AddReagentForm(QDialog):
Returns:
dict: Output info
"""
return dict(name=self.name_input.currentText().strip(),
lot=self.lot_input.text().strip(),
"""
return dict(name=self.name_input.currentText().strip(),
lot=self.lot_input.text().strip(),
expiry=self.exp_input.date().toPyDate(),
role=self.type_input.currentText().strip())
def update_names(self):
"""
Updates reagent names form field with examples from reagent type
"""
"""
# logger.debug(self.type_input.currentText())
self.name_input.clear()
lookup = Reagent.query(reagent_role=self.type_input.currentText())
self.name_input.addItems(list(set([item.name for item in lookup])))
class ReportDatePicker(QDialog):
"""
custom dialog to ask for report start/stop dates
"""
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("Select Report Date Range")
# NOTE: make confirm/reject buttons
QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
# NOTE: widgets to ask for dates
self.start_date = QDateEdit(calendarPopup=True)
self.start_date.setObjectName("start_date")
self.start_date.setDate(QDate.currentDate())
self.end_date = QDateEdit(calendarPopup=True)
self.end_date.setObjectName("end_date")
self.end_date.setDate(QDate.currentDate())
self.layout = QVBoxLayout()
self.layout.addWidget(QLabel("Start Date"))
self.layout.addWidget(self.start_date)
self.layout.addWidget(QLabel("End Date"))
self.layout.addWidget(self.end_date)
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
def parse_form(self) -> dict:
"""
Converts information in this object to a dict
Returns:
dict: output dict.
"""
return dict(start_date=self.start_date.date().toPyDate(), end_date = self.end_date.date().toPyDate())
# class ReportDatePicker(QDialog):
# """
# custom dialog to ask for report start/stop dates
# """
# def __init__(self) -> None:
# super().__init__()
# self.setWindowTitle("Select Report Date Range")
# # NOTE: make confirm/reject buttons
# QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
# self.buttonBox = QDialogButtonBox(QBtn)
# self.buttonBox.accepted.connect(self.accept)
# self.buttonBox.rejected.connect(self.reject)
# # NOTE: widgets to ask for dates
# self.start_date = QDateEdit(calendarPopup=True)
# self.start_date.setObjectName("start_date")
# self.start_date.setDate(QDate.currentDate())
# self.end_date = QDateEdit(calendarPopup=True)
# self.end_date.setObjectName("end_date")
# self.end_date.setDate(QDate.currentDate())
# self.layout = QVBoxLayout()
# self.layout.addWidget(QLabel("Start Date"))
# self.layout.addWidget(self.start_date)
# self.layout.addWidget(QLabel("End Date"))
# self.layout.addWidget(self.end_date)
# self.layout.addWidget(self.buttonBox)
# self.setLayout(self.layout)
#
# def parse_form(self) -> dict:
# """
# Converts information in this object to a dict
#
# Returns:
# dict: output dict.
# """
# return dict(start_date=self.start_date.date().toPyDate(), end_date = self.end_date.date().toPyDate())
class LogParser(QDialog):
@@ -160,13 +166,13 @@ class LogParser(QDialog):
def filelookup(self):
"""
Select file to search
"""
"""
self.fname = select_open_file(self, "tabular")
def runsearch(self):
"""
Gets total/percent occurences of string in tabular file.
"""
"""
count: int = 0
total: int = 0
# logger.debug(f"Current search term: {self.phrase_looker.currentText()}")
@@ -177,7 +183,7 @@ class LogParser(QDialog):
for line in chunk:
if self.phrase_looker.currentText().lower() in line.lower():
count += 1
percent = (count/total)*100
percent = (count / total) * 100
msg = f"I found {count} instances of the search phrase out of {total} = {percent:.2f}%."
status = "Information"
except AttributeError:
@@ -186,3 +192,56 @@ class LogParser(QDialog):
dlg = AlertPop(message=msg, status=status)
dlg.exec()
class StartEndDatePicker(QWidget):
"""
custom widget to pick start and end dates for controls graphs
"""
def __init__(self, default_start: int) -> None:
super().__init__()
self.start_date = QDateEdit(calendarPopup=True)
# NOTE: start date is two months prior to end date by default
default_start = QDate.currentDate().addDays(default_start)
self.start_date.setDate(default_start)
self.end_date = QDateEdit(calendarPopup=True)
self.end_date.setDate(QDate.currentDate())
self.layout = QHBoxLayout()
self.layout.addWidget(QLabel("Start Date"))
self.layout.addWidget(self.start_date)
self.layout.addWidget(QLabel("End Date"))
self.layout.addWidget(self.end_date)
self.setLayout(self.layout)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
def sizeHint(self) -> QSize:
return QSize(80, 20)
def save_pdf(obj: QWebEngineView, filename: Path):
page_layout = QPageLayout()
page_layout.setPageSize(QPageSize(QPageSize.PageSizeId.A4))
page_layout.setOrientation(QPageLayout.Orientation.Portrait)
page_layout.setMargins(QMarginsF(25, 25, 25, 25))
obj.page().printToPdf(filename.absolute().__str__(), page_layout)
# subclass
class CheckableComboBox(QComboBox):
# once there is a checkState set, it is rendered
# here we assume default Unchecked
def addItem(self, item, header: bool = False):
super(CheckableComboBox, self).addItem(item)
item: QStandardItem = self.model().item(self.count() - 1, 0)
if not header:
item.setFlags(Qt.ItemFlag.ItemIsUserCheckable | Qt.ItemFlag.ItemIsEnabled)
item.setCheckState(Qt.CheckState.Checked)
def itemChecked(self, index):
item = self.model().item(index, 0)
return item.checkState() == Qt.CheckState.Checked
def changed(self):
logger.debug("emitting updated")
self.updated.emit()

View File

@@ -10,8 +10,9 @@ from PyQt6.QtWebChannel import QWebChannel
from PyQt6.QtCore import Qt, pyqtSlot, QMarginsF
from jinja2 import TemplateNotFound
from backend.db.models import BasicSubmission, BasicSample, Reagent, KitType
from tools import is_power_user, html_to_pdf, jinja_template_loading
from tools import is_power_user, jinja_template_loading
from .functions import select_save_file
from .misc import save_pdf
from pathlib import Path
import logging
from getpass import getuser
@@ -177,11 +178,12 @@ class SubmissionDetails(QDialog):
Renders submission to html, then creates and saves .pdf file to user selected file.
"""
fname = select_save_file(obj=self, default_name=self.export_plate, extension="pdf")
page_layout = QPageLayout()
page_layout.setPageSize(QPageSize(QPageSize.PageSizeId.A4))
page_layout.setOrientation(QPageLayout.Orientation.Portrait)
page_layout.setMargins(QMarginsF(25, 25, 25, 25))
self.webview.page().printToPdf(fname.with_suffix(".pdf").__str__(), page_layout)
# page_layout = QPageLayout()
# page_layout.setPageSize(QPageSize(QPageSize.PageSizeId.A4))
# page_layout.setOrientation(QPageLayout.Orientation.Portrait)
# page_layout.setMargins(QMarginsF(25, 25, 25, 25))
# self.webview.page().printToPdf(fname.with_suffix(".pdf").__str__(), page_layout)
save_pdf(obj=self, filename=fname)
class SubmissionComment(QDialog):
"""

View File

@@ -10,7 +10,7 @@ from backend.db.models import BasicSubmission
from backend.excel import ReportMaker
from tools import Report, Result, report_result
from .functions import select_save_file, select_open_file
from .misc import ReportDatePicker
# from .misc import ReportDatePicker
logger = logging.getLogger(f"submissions.{__name__}")
@@ -226,32 +226,32 @@ class SubmissionsSheet(QTableView):
report.add_result(Result(msg=f"We added {count} logs to the database.", status='Information'))
return report
@report_result
def generate_report(self, *args):
"""
Make a report
"""
report = Report()
result = self.generate_report_function()
report.add_result(result)
return report
def generate_report_function(self):
"""
Generate a summary of activities for a time period
Args:
obj (QMainWindow): original app window
Returns:
Tuple[QMainWindow, dict]: Collection of new main app window and result dict
"""
report = Report()
# NOTE: ask for date ranges
dlg = ReportDatePicker()
if dlg.exec():
info = dlg.parse_form()
fname = select_save_file(obj=self, default_name=f"Submissions_Report_{info['start_date']}-{info['end_date']}.xlsx", extension="xlsx")
rp = ReportMaker(start_date=info['start_date'], end_date=info['end_date'])
rp.write_report(filename=fname, obj=self)
return report
# @report_result
# def generate_report(self, *args):
# """
# Make a report
# """
# report = Report()
# result = self.generate_report_function()
# report.add_result(result)
# return report
#
# def generate_report_function(self):
# """
# Generate a summary of activities for a time period
#
# Args:
# obj (QMainWindow): original app window
#
# Returns:
# Tuple[QMainWindow, dict]: Collection of new main app window and result dict
# """
# report = Report()
# # NOTE: ask for date ranges
# dlg = ReportDatePicker()
# if dlg.exec():
# info = dlg.parse_form()
# fname = select_save_file(obj=self, default_name=f"Submissions_Report_{info['start_date']}-{info['end_date']}.xlsx", extension="xlsx")
# rp = ReportMaker(start_date=info['start_date'], end_date=info['end_date'])
# rp.write_report(filename=fname, obj=self)
# return report

View File

@@ -0,0 +1,78 @@
from PyQt6.QtCore import QSignalBlocker
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWidgets import QWidget, QGridLayout, QPushButton, QComboBox, QLabel
from backend.db import Organization
from backend.excel import ReportMaker
from tools import Report
from .misc import StartEndDatePicker, save_pdf, CheckableComboBox
from .functions import select_save_file
import logging
logger = logging.getLogger(f"submissions.{__name__}")
class Summary(QWidget):
def __init__(self, parent: QWidget) -> None:
super().__init__(parent)
self.app = self.parent().parent()
# logger.debug(f"\n\n{self.app}\n\n")
self.report = Report()
self.datepicker = StartEndDatePicker(default_start=-31)
self.webview = QWebEngineView()
self.datepicker.start_date.dateChanged.connect(self.get_report)
self.datepicker.end_date.dateChanged.connect(self.get_report)
self.layout = QGridLayout(self)
self.layout.addWidget(self.datepicker, 0, 0, 1, 2)
self.save_excel_button = QPushButton("Save Excel", parent=self)
self.save_excel_button.pressed.connect(self.save_excel)
self.save_pdf_button = QPushButton("Save PDF", parent=self)
self.save_pdf_button.pressed.connect(self.save_pdf)
self.org_select = CheckableComboBox()
self.org_select.setEditable(False)
self.org_select.addItem("Select", header=True)
for org in [org.name for org in Organization.query()]:
self.org_select.addItem(org)
self.org_select.model().itemChanged.connect(self.get_report)
# self.org_select.itemChecked.connect(self.get_report)
self.layout.addWidget(self.save_excel_button, 0, 2, 1, 1)
self.layout.addWidget(self.save_pdf_button, 0, 3, 1, 1)
self.layout.addWidget(self.webview, 2, 0, 1, 4)
self.layout.addWidget(QLabel("Client"), 1, 0, 1, 1)
self.layout.addWidget(self.org_select, 1, 1, 1, 3)
self.setLayout(self.layout)
self.get_report()
def get_report(self):
orgs = [self.org_select.itemText(i) for i in range(self.org_select.count()) if self.org_select.itemChecked(i)]
if self.datepicker.start_date.date() > self.datepicker.end_date.date():
logger.warning("Start date after end date is not allowed!")
lastmonth = self.datepicker.end_date.date().addDays(-31)
# NOTE: block signal that will rerun controls getter and set start date
# Without triggering this function again
with QSignalBlocker(self.datepicker.start_date) as blocker:
self.datepicker.start_date.setDate(lastmonth)
self.get_report()
return
# NOTE: convert to python useable date objects
self.start_date = self.datepicker.start_date.date().toPyDate()
self.end_date = self.datepicker.end_date.date().toPyDate()
self.report_obj = ReportMaker(start_date=self.start_date, end_date=self.end_date, organizations=orgs)
self.webview.setHtml(self.report_obj.html)
if self.report_obj.subs:
self.save_pdf_button.setEnabled(True)
self.save_excel_button.setEnabled(True)
else:
self.save_pdf_button.setEnabled(False)
self.save_excel_button.setEnabled(False)
def save_excel(self):
fname = select_save_file(self, default_name=f"Report {self.start_date.strftime('%Y%m%d')} - {self.end_date.strftime('%Y%m%d')}", extension="xlsx")
self.report_obj.write_report(fname, obj=self)
def save_pdf(self):
fname = select_save_file(obj=self,
default_name=f"Report {self.start_date.strftime('%Y%m%d')} - {self.end_date.strftime('%Y%m%d')}",
extension="pdf")
save_pdf(obj=self.webview, filename=fname)