Can now calculate turnaround time including holidays.

This commit is contained in:
lwark
2024-11-25 13:34:02 -06:00
parent 7d1e6dc606
commit 7f0b7feb5d
13 changed files with 533 additions and 300 deletions

View File

@@ -142,97 +142,97 @@ class Control(BaseClass):
def __repr__(self) -> str:
return f"<{self.controltype_name}({self.name})>"
# @classmethod
# @setup_lookup
# def query(cls,
# submission_type: str | None = None,
# subtype: str | None = None,
# start_date: date | str | int | None = None,
# end_date: date | str | int | None = None,
# control_name: str | None = None,
# limit: int = 0, **kwargs
# ) -> Control | List[Control]:
# """
# Lookup control objects in the database based on a number of parameters.
#
# Args:
# submission_type (str | None, optional): Control archetype. Defaults to None.
# start_date (date | str | int | None, optional): Beginning date to search by. Defaults to 2023-01-01 if end_date not None.
# end_date (date | str | int | None, optional): End date to search by. Defaults to today if start_date not None.
# control_name (str | None, optional): Name of control. Defaults to None.
# limit (int, optional): Maximum number of results to return (0 = all). Defaults to 0.
#
# Returns:
# PCRControl|List[PCRControl]: Control object of interest.
# """
# from backend.db import SubmissionType
# query: Query = cls.__database_session__.query(cls)
# match submission_type:
# case str():
# from backend import BasicSubmission, SubmissionType
# # logger.debug(f"Lookup controls by SubmissionType str: {submission_type}")
# query = query.join(BasicSubmission).join(SubmissionType).filter(SubmissionType.name == submission_type)
# case SubmissionType():
# from backend import BasicSubmission
# # logger.debug(f"Lookup controls by SubmissionType: {submission_type}")
# query = query.join(BasicSubmission).filter(BasicSubmission.submission_type_name == submission_type.name)
# case _:
# pass
# # NOTE: by control type
# match subtype:
# case str():
# if cls.__name__ == "Control":
# raise ValueError(f"Cannot query base class Control with subtype.")
# elif cls.__name__ == "IridaControl":
# query = query.filter(cls.subtype == subtype)
# else:
# try:
# query = query.filter(cls.subtype == subtype)
# except AttributeError as e:
# logger.error(e)
# case _:
# pass
# # NOTE: by date range
# if start_date is not None and end_date is None:
# logger.warning(f"Start date with no end date, using today.")
# end_date = date.today()
# if end_date is not None and start_date is None:
# logger.warning(f"End date with no start date, using 90 days ago.")
# # start_date = date(2023, 1, 1)
# start_date = date.today() - timedelta(days=90)
# if start_date is not None:
# match start_date:
# case date():
# # logger.debug(f"Lookup control by start date({start_date})")
# start_date = start_date.strftime("%Y-%m-%d")
# case int():
# # logger.debug(f"Lookup control by ordinal start date {start_date}")
# start_date = datetime.fromordinal(
# datetime(1900, 1, 1).toordinal() + start_date - 2).date().strftime("%Y-%m-%d")
# case _:
# # logger.debug(f"Lookup control with parsed start date {start_date}")
# start_date = parse(start_date).strftime("%Y-%m-%d")
# match end_date:
# case date():
# # logger.debug(f"Lookup control by end date({end_date})")
# end_date = end_date.strftime("%Y-%m-%d")
# case int():
# # logger.debug(f"Lookup control by ordinal end date {end_date}")
# end_date = datetime.fromordinal(datetime(1900, 1, 1).toordinal() + end_date - 2).date().strftime(
# "%Y-%m-%d")
# case _:
# # logger.debug(f"Lookup control with parsed end date {end_date}")
# end_date = parse(end_date).strftime("%Y-%m-%d")
# # logger.debug(f"Looking up BasicSubmissions from start date: {start_date} and end date: {end_date}")
# query = query.filter(cls.submitted_date.between(start_date, end_date))
# match control_name:
# case str():
# # logger.debug(f"Lookup control by name {control_name}")
# query = query.filter(cls.name.startswith(control_name))
# limit = 1
# case _:
# pass
# return cls.execute_query(query=query, limit=limit)
@classmethod
@setup_lookup
def query(cls,
submission_type: str | None = None,
subtype: str | None = None,
start_date: date | str | int | None = None,
end_date: date | str | int | None = None,
name: str | None = None,
limit: int = 0, **kwargs
) -> Control | List[Control]:
"""
Lookup control objects in the database based on a number of parameters.
Args:
submission_type (str | None, optional): Control archetype. Defaults to None.
start_date (date | str | int | None, optional): Beginning date to search by. Defaults to 2023-01-01 if end_date not None.
end_date (date | str | int | None, optional): End date to search by. Defaults to today if start_date not None.
name (str | None, optional): Name of control. Defaults to None.
limit (int, optional): Maximum number of results to return (0 = all). Defaults to 0.
Returns:
Control|List[Control]: Control object of interest.
"""
from backend.db import SubmissionType
query: Query = cls.__database_session__.query(cls)
match submission_type:
case str():
from backend import BasicSubmission, SubmissionType
# logger.debug(f"Lookup controls by SubmissionType str: {submission_type}")
query = query.join(BasicSubmission).join(SubmissionType).filter(SubmissionType.name == submission_type)
case SubmissionType():
from backend import BasicSubmission
# logger.debug(f"Lookup controls by SubmissionType: {submission_type}")
query = query.join(BasicSubmission).filter(BasicSubmission.submission_type_name == submission_type.name)
case _:
pass
# NOTE: by control type
match subtype:
case str():
if cls.__name__ == "Control":
raise ValueError(f"Cannot query base class Control with subtype.")
elif cls.__name__ == "IridaControl":
query = query.filter(cls.subtype == subtype)
else:
try:
query = query.filter(cls.subtype == subtype)
except AttributeError as e:
logger.error(e)
case _:
pass
# NOTE: by date range
if start_date is not None and end_date is None:
logger.warning(f"Start date with no end date, using today.")
end_date = date.today()
if end_date is not None and start_date is None:
logger.warning(f"End date with no start date, using 90 days ago.")
# start_date = date(2023, 1, 1)
start_date = date.today() - timedelta(days=90)
if start_date is not None:
match start_date:
case date():
# logger.debug(f"Lookup control by start date({start_date})")
start_date = start_date.strftime("%Y-%m-%d")
case int():
# logger.debug(f"Lookup control by ordinal start date {start_date}")
start_date = datetime.fromordinal(
datetime(1900, 1, 1).toordinal() + start_date - 2).date().strftime("%Y-%m-%d")
case _:
# logger.debug(f"Lookup control with parsed start date {start_date}")
start_date = parse(start_date).strftime("%Y-%m-%d")
match end_date:
case date():
# logger.debug(f"Lookup control by end date({end_date})")
end_date = end_date.strftime("%Y-%m-%d")
case int():
# logger.debug(f"Lookup control by ordinal end date {end_date}")
end_date = datetime.fromordinal(datetime(1900, 1, 1).toordinal() + end_date - 2).date().strftime(
"%Y-%m-%d")
case _:
# logger.debug(f"Lookup control with parsed end date {end_date}")
end_date = parse(end_date).strftime("%Y-%m-%d")
# logger.debug(f"Looking up BasicSubmissions from start date: {start_date} and end date: {end_date}")
query = query.filter(cls.submitted_date.between(start_date, end_date))
match name:
case str():
# logger.debug(f"Lookup control by name {control_name}")
query = query.filter(cls.name.startswith(name))
limit = 1
case _:
pass
return cls.execute_query(query=query, limit=limit)
@classmethod
def find_polymorphic_subclass(cls, polymorphic_identity: str | ControlType | None = None,
@@ -323,82 +323,82 @@ class PCRControl(Control):
return dict(name=self.name, ct=self.ct, subtype=self.subtype, target=self.target, reagent_lot=self.reagent_lot,
submitted_date=self.submitted_date.date())
@classmethod
@setup_lookup
def query(cls,
submission_type: str | None = None,
start_date: date | str | int | None = None,
end_date: date | str | int | None = None,
control_name: str | None = None,
limit: int = 0
) -> Control | List[Control]:
"""
Lookup control objects in the database based on a number of parameters.
Args:
submission_type (str | None, optional): Control archetype. Defaults to None.
start_date (date | str | int | None, optional): Beginning date to search by. Defaults to 2023-01-01 if end_date not None.
end_date (date | str | int | None, optional): End date to search by. Defaults to today if start_date not None.
control_name (str | None, optional): Name of control. Defaults to None.
limit (int, optional): Maximum number of results to return (0 = all). Defaults to 0.
Returns:
PCRControl|List[PCRControl]: Control object of interest.
"""
from backend.db import SubmissionType
query: Query = cls.__database_session__.query(cls)
# NOTE: by date range
if start_date is not None and end_date is None:
logger.warning(f"Start date with no end date, using today.")
end_date = date.today()
if end_date is not None and start_date is None:
logger.warning(f"End date with no start date, using 90 days ago.")
# start_date = date(2023, 1, 1)
start_date = date.today() - timedelta(days=90)
if start_date is not None:
match start_date:
case date():
# logger.debug(f"Lookup control by start date({start_date})")
start_date = start_date.strftime("%Y-%m-%d")
case int():
# logger.debug(f"Lookup control by ordinal start date {start_date}")
start_date = datetime.fromordinal(
datetime(1900, 1, 1).toordinal() + start_date - 2).date().strftime("%Y-%m-%d")
case _:
# logger.debug(f"Lookup control with parsed start date {start_date}")
start_date = parse(start_date).strftime("%Y-%m-%d")
match end_date:
case date():
# logger.debug(f"Lookup control by end date({end_date})")
end_date = end_date.strftime("%Y-%m-%d")
case int():
# logger.debug(f"Lookup control by ordinal end date {end_date}")
end_date = datetime.fromordinal(datetime(1900, 1, 1).toordinal() + end_date - 2).date().strftime(
"%Y-%m-%d")
case _:
# logger.debug(f"Lookup control with parsed end date {end_date}")
end_date = parse(end_date).strftime("%Y-%m-%d")
# logger.debug(f"Looking up BasicSubmissions from start date: {start_date} and end date: {end_date}")
query = query.filter(cls.submitted_date.between(start_date, end_date))
match submission_type:
case str():
from backend import BasicSubmission, SubmissionType
# logger.debug(f"Lookup controls by SubmissionType str: {submission_type}")
query = query.join(BasicSubmission).join(SubmissionType).filter(SubmissionType.name == submission_type)
case SubmissionType():
from backend import BasicSubmission
# logger.debug(f"Lookup controls by SubmissionType: {submission_type}")
query = query.join(BasicSubmission).filter(BasicSubmission.submission_type_name==submission_type.name)
case _:
pass
match control_name:
case str():
# logger.debug(f"Lookup control by name {control_name}")
query = query.filter(cls.name.startswith(control_name))
limit = 1
case _:
pass
return cls.execute_query(query=query, limit=limit)
# @classmethod
# @setup_lookup
# def query(cls,
# submission_type: str | None = None,
# start_date: date | str | int | None = None,
# end_date: date | str | int | None = None,
# name: str | None = None,
# limit: int = 0
# ) -> Control | List[Control]:
# """
# Lookup control objects in the database based on a number of parameters.
#
# Args:
# submission_type (str | None, optional): Control archetype. Defaults to None.
# start_date (date | str | int | None, optional): Beginning date to search by. Defaults to 2023-01-01 if end_date not None.
# end_date (date | str | int | None, optional): End date to search by. Defaults to today if start_date not None.
# control_name (str | None, optional): Name of control. Defaults to None.
# limit (int, optional): Maximum number of results to return (0 = all). Defaults to 0.
#
# Returns:
# PCRControl|List[PCRControl]: Control object of interest.
# """
# from backend.db import SubmissionType
# query: Query = cls.__database_session__.query(cls)
# # NOTE: by date range
# if start_date is not None and end_date is None:
# logger.warning(f"Start date with no end date, using today.")
# end_date = date.today()
# if end_date is not None and start_date is None:
# logger.warning(f"End date with no start date, using 90 days ago.")
# # start_date = date(2023, 1, 1)
# start_date = date.today() - timedelta(days=90)
# if start_date is not None:
# match start_date:
# case date():
# # logger.debug(f"Lookup control by start date({start_date})")
# start_date = start_date.strftime("%Y-%m-%d")
# case int():
# # logger.debug(f"Lookup control by ordinal start date {start_date}")
# start_date = datetime.fromordinal(
# datetime(1900, 1, 1).toordinal() + start_date - 2).date().strftime("%Y-%m-%d")
# case _:
# # logger.debug(f"Lookup control with parsed start date {start_date}")
# start_date = parse(start_date).strftime("%Y-%m-%d")
# match end_date:
# case date():
# # logger.debug(f"Lookup control by end date({end_date})")
# end_date = end_date.strftime("%Y-%m-%d")
# case int():
# # logger.debug(f"Lookup control by ordinal end date {end_date}")
# end_date = datetime.fromordinal(datetime(1900, 1, 1).toordinal() + end_date - 2).date().strftime(
# "%Y-%m-%d")
# case _:
# # logger.debug(f"Lookup control with parsed end date {end_date}")
# end_date = parse(end_date).strftime("%Y-%m-%d")
# # logger.debug(f"Looking up BasicSubmissions from start date: {start_date} and end date: {end_date}")
# query = query.filter(cls.submitted_date.between(start_date, end_date))
# match submission_type:
# case str():
# from backend import BasicSubmission, SubmissionType
# # logger.debug(f"Lookup controls by SubmissionType str: {submission_type}")
# query = query.join(BasicSubmission).join(SubmissionType).filter(SubmissionType.name == submission_type)
# case SubmissionType():
# from backend import BasicSubmission
# # logger.debug(f"Lookup controls by SubmissionType: {submission_type}")
# query = query.join(BasicSubmission).filter(BasicSubmission.submission_type_name==submission_type.name)
# case _:
# pass
# match control_name:
# case str():
# # logger.debug(f"Lookup control by name {control_name}")
# query = query.filter(cls.name.startswith(control_name))
# limit = 1
# case _:
# pass
# return cls.execute_query(query=query, limit=limit)
@classmethod
@report_result
@@ -432,7 +432,7 @@ class PCRControl(Control):
def to_pydantic(self):
from backend.validators import PydPCRControl
return PydPCRControl(**self.to_sub_dict())
return PydPCRControl(**self.to_sub_dict(), controltype_name=self.controltype_name, submission_id=self.submission_id)
class IridaControl(Control):
@@ -569,76 +569,76 @@ class IridaControl(Control):
cols = []
return cols
@classmethod
@setup_lookup
def query(cls,
sub_type: str | None = None,
start_date: date | str | int | None = None,
end_date: date | str | int | None = None,
control_name: str | None = None,
limit: int = 0
) -> Control | List[Control]:
"""
Lookup control objects in the database based on a number of parameters.
Args:
sub_type (models.ControlType | str | None, optional): Control archetype. Defaults to None.
start_date (date | str | int | None, optional): Beginning date to search by. Defaults to 2023-01-01 if end_date not None.
end_date (date | str | int | None, optional): End date to search by. Defaults to today if start_date not None.
control_name (str | None, optional): Name of control. Defaults to None.
limit (int, optional): Maximum number of results to return (0 = all). Defaults to 0.
Returns:
models.Control|List[models.Control]: Control object of interest.
"""
query: Query = cls.__database_session__.query(cls)
# NOTE: by control type
match sub_type:
case str():
query = query.filter(cls.subtype == sub_type)
case _:
pass
# NOTE: If one date exists, we need the other one to exist as well.
if start_date is not None and end_date is None:
logger.warning(f"Start date with no end date, using today.")
end_date = date.today()
if end_date is not None and start_date is None:
logger.warning(f"End date with no start date, using 90 days ago.")
# start_date = date(2023, 1, 1)
start_date = date.today() - timedelta(days=90)
if start_date is not None:
match start_date:
case date():
# logger.debug(f"Lookup control by start date({start_date})")
start_date = start_date.strftime("%Y-%m-%d")
case int():
# logger.debug(f"Lookup control by ordinal start date {start_date}")
start_date = datetime.fromordinal(
datetime(1900, 1, 1).toordinal() + start_date - 2).date().strftime("%Y-%m-%d")
case _:
# logger.debug(f"Lookup control with parsed start date {start_date}")
start_date = parse(start_date).strftime("%Y-%m-%d")
match end_date:
case date():
# logger.debug(f"Lookup control by end date({end_date})")
end_date = end_date.strftime("%Y-%m-%d")
case int():
# logger.debug(f"Lookup control by ordinal end date {end_date}")
end_date = datetime.fromordinal(datetime(1900, 1, 1).toordinal() + end_date - 2).date().strftime(
"%Y-%m-%d")
case _:
# logger.debug(f"Lookup control with parsed end date {end_date}")
end_date = parse(end_date).strftime("%Y-%m-%d")
# logger.debug(f"Looking up BasicSubmissions from start date: {start_date} and end date: {end_date}")
query = query.filter(cls.submitted_date.between(start_date, end_date))
match control_name:
case str():
# logger.debug(f"Lookup control by name {control_name}")
query = query.filter(cls.name.startswith(control_name))
limit = 1
case _:
pass
return cls.execute_query(query=query, limit=limit)
# @classmethod
# @setup_lookup
# def query(cls,
# sub_type: str | None = None,
# start_date: date | str | int | None = None,
# end_date: date | str | int | None = None,
# control_name: str | None = None,
# limit: int = 0
# ) -> Control | List[Control]:
# """
# Lookup control objects in the database based on a number of parameters.
#
# Args:
# sub_type (models.ControlType | str | None, optional): Control archetype. Defaults to None.
# start_date (date | str | int | None, optional): Beginning date to search by. Defaults to 2023-01-01 if end_date not None.
# end_date (date | str | int | None, optional): End date to search by. Defaults to today if start_date not None.
# control_name (str | None, optional): Name of control. Defaults to None.
# limit (int, optional): Maximum number of results to return (0 = all). Defaults to 0.
#
# Returns:
# models.Control|List[models.Control]: Control object of interest.
# """
# query: Query = cls.__database_session__.query(cls)
# # NOTE: by control type
# match sub_type:
# case str():
# query = query.filter(cls.subtype == sub_type)
# case _:
# pass
# # NOTE: If one date exists, we need the other one to exist as well.
# if start_date is not None and end_date is None:
# logger.warning(f"Start date with no end date, using today.")
# end_date = date.today()
# if end_date is not None and start_date is None:
# logger.warning(f"End date with no start date, using 90 days ago.")
# # start_date = date(2023, 1, 1)
# start_date = date.today() - timedelta(days=90)
# if start_date is not None:
# match start_date:
# case date():
# # logger.debug(f"Lookup control by start date({start_date})")
# start_date = start_date.strftime("%Y-%m-%d")
# case int():
# # logger.debug(f"Lookup control by ordinal start date {start_date}")
# start_date = datetime.fromordinal(
# datetime(1900, 1, 1).toordinal() + start_date - 2).date().strftime("%Y-%m-%d")
# case _:
# # logger.debug(f"Lookup control with parsed start date {start_date}")
# start_date = parse(start_date).strftime("%Y-%m-%d")
# match end_date:
# case date():
# # logger.debug(f"Lookup control by end date({end_date})")
# end_date = end_date.strftime("%Y-%m-%d")
# case int():
# # logger.debug(f"Lookup control by ordinal end date {end_date}")
# end_date = datetime.fromordinal(datetime(1900, 1, 1).toordinal() + end_date - 2).date().strftime(
# "%Y-%m-%d")
# case _:
# # logger.debug(f"Lookup control with parsed end date {end_date}")
# end_date = parse(end_date).strftime("%Y-%m-%d")
# # logger.debug(f"Looking up BasicSubmissions from start date: {start_date} and end date: {end_date}")
# query = query.filter(cls.submitted_date.between(start_date, end_date))
# match control_name:
# case str():
# # logger.debug(f"Lookup control by name {control_name}")
# query = query.filter(cls.name.startswith(control_name))
# limit = 1
# case _:
# pass
# return cls.execute_query(query=query, limit=limit)
@classmethod
def make_parent_buttons(cls, parent: QWidget) -> None:
@@ -828,7 +828,7 @@ class IridaControl(Control):
return df, previous_dates
# NOTE: if date was changed, rerun with new date
else:
logger.warning(f"Date check failed, running recursion")
# logger.warning(f"Date check failed, running recursion")
df, previous_dates = cls.check_date(df, item, previous_dates)
return df, previous_dates