Bug fixing for new AddEdit forms.
This commit is contained in:
@@ -243,7 +243,10 @@ class BaseClass(Base):
|
||||
@classmethod
|
||||
def get_pydantic_model(cls):
|
||||
from backend.validators import pydant
|
||||
model = getattr(pydant, f"Pyd{cls.__name__}")
|
||||
try:
|
||||
model = getattr(pydant, f"Pyd{cls.__name__}")
|
||||
except AttributeError:
|
||||
return None
|
||||
return model
|
||||
|
||||
|
||||
|
||||
@@ -286,6 +286,10 @@ class Control(BaseClass):
|
||||
"""
|
||||
return None
|
||||
|
||||
def delete(self):
|
||||
self.__database_session__.delete(self)
|
||||
self.__database_session__.commit()
|
||||
|
||||
|
||||
class PCRControl(Control):
|
||||
"""
|
||||
@@ -296,7 +300,7 @@ class PCRControl(Control):
|
||||
subtype = Column(String(16)) #: PC or NC
|
||||
target = Column(String(16)) #: N1, N2, etc.
|
||||
ct = Column(FLOAT) #: PCR result
|
||||
reagent_lot = Column(String(64), ForeignKey("_reagent.name", ondelete="SET NULL",
|
||||
reagent_lot = Column(String(64), ForeignKey("_reagent.lot", ondelete="SET NULL",
|
||||
name="fk_reagent_lot"))
|
||||
reagent = relationship("Reagent", foreign_keys=reagent_lot) #: reagent used for this control
|
||||
|
||||
|
||||
@@ -540,6 +540,24 @@ class Reagent(BaseClass, LogMixin):
|
||||
report.add_result(Result(msg=f"Updating last used {rt} was not performed.", status="Information"))
|
||||
return report
|
||||
|
||||
@classmethod
|
||||
def query_or_create(cls, **kwargs) -> Reagent:
|
||||
from backend.validators.pydant import PydReagent
|
||||
new = False
|
||||
instance = cls.query(**kwargs)
|
||||
if not instance or isinstance(instance, list):
|
||||
if "role" not in kwargs:
|
||||
try:
|
||||
kwargs['role'] = kwargs['name']
|
||||
except KeyError:
|
||||
pass
|
||||
instance = PydReagent(**kwargs)
|
||||
new = True
|
||||
instance, _ = instance.toSQL()
|
||||
logger.debug(f"Instance: {instance}")
|
||||
return instance, new
|
||||
|
||||
|
||||
@classmethod
|
||||
@setup_lookup
|
||||
def query(cls,
|
||||
|
||||
@@ -936,14 +936,20 @@ class BasicSubmission(BaseClass, LogMixin):
|
||||
Generator[dict, None, None]: Dictionaries of row values.
|
||||
"""
|
||||
location_map = cls.get_submission_type().sample_map['pcr_controls']
|
||||
# logger.debug(f"Location map: {location_map}")
|
||||
submission = cls.query(rsl_plate_num=rsl_plate_num)
|
||||
name_column = 1
|
||||
for item in location_map:
|
||||
logger.debug(f"Checking {item}")
|
||||
worksheet = xl[item['sheet']]
|
||||
for iii, row in enumerate(worksheet.iter_rows(max_row=len(worksheet['A']), max_col=name_column), start=1):
|
||||
logger.debug(f"Checking row {row}, {iii}")
|
||||
for cell in row:
|
||||
logger.debug(f"Checking cell: {cell}, with value {cell.value} against {item['name']}")
|
||||
if cell.value == item['name']:
|
||||
subtype, target = item['name'].split("-")
|
||||
subtype, _ = item['name'].split("-")
|
||||
target = item['target']
|
||||
logger.debug(f"Subtype: {subtype}, target: {target}")
|
||||
ct = worksheet.cell(row=iii, column=item['ct_column']).value
|
||||
# NOTE: Kind of a stop gap solution to find control reagents.
|
||||
if subtype == "PC":
|
||||
@@ -955,6 +961,9 @@ class BasicSubmission(BaseClass, LogMixin):
|
||||
ctrl = next((assoc.reagent for assoc in submission.submission_reagent_associations
|
||||
if any(["molecular grade water" in item.name.lower() for item in
|
||||
assoc.reagent.role])), None)
|
||||
else:
|
||||
ctrl = None
|
||||
logger.debug(f"Control reagent: {ctrl.__dict__}")
|
||||
try:
|
||||
ct = float(ct)
|
||||
except ValueError:
|
||||
@@ -963,13 +972,15 @@ class BasicSubmission(BaseClass, LogMixin):
|
||||
ctrl = ctrl.lot
|
||||
else:
|
||||
ctrl = None
|
||||
yield dict(
|
||||
name=f"{rsl_plate_num}<{item['name']}>",
|
||||
output = dict(
|
||||
name=f"{rsl_plate_num}<{item['name']}-{target}>",
|
||||
ct=ct,
|
||||
subtype=subtype,
|
||||
target=target,
|
||||
reagent_lot=ctrl
|
||||
)
|
||||
logger.debug(f"Control output: {pformat(output)}")
|
||||
yield output
|
||||
|
||||
@classmethod
|
||||
def filename_template(cls) -> str:
|
||||
@@ -1663,10 +1674,12 @@ class Wastewater(BasicSubmission):
|
||||
submitted_date = datetime.strptime(" ".join(parser.pcr['run_start_date/time'].split(" ")[:-1]),
|
||||
"%Y-%m-%d %I:%M:%S %p")
|
||||
for control in pcr_controls:
|
||||
logger.debug(f"Control coming into save: {control}")
|
||||
new_control = PCRControl(**control)
|
||||
new_control.submitted_date = submitted_date
|
||||
new_control.controltype = controltype
|
||||
new_control.submission = self
|
||||
logger.debug(f"Control coming into save: {new_control.__dict__}")
|
||||
new_control.save()
|
||||
return report
|
||||
|
||||
|
||||
@@ -257,9 +257,10 @@ class ReagentParser(object):
|
||||
extraction_kit = extraction_kit['value']
|
||||
self.kit_object = KitType.query(name=extraction_kit)
|
||||
self.map = self.fetch_kit_info_map(submission_type=submission_type)
|
||||
logger.debug(f"Setting map: {self.map}")
|
||||
self.xl = xl
|
||||
|
||||
@report_result
|
||||
# @report_result
|
||||
def fetch_kit_info_map(self, submission_type: str | SubmissionType) -> Tuple[Report, dict]:
|
||||
"""
|
||||
Gets location of kit reagents from database
|
||||
@@ -298,7 +299,8 @@ class ReagentParser(object):
|
||||
msg=f"No kit map found for {self.kit_object.name}.\n\n"
|
||||
f"Are you sure you put the right kit in:\n\n{location_string}?",
|
||||
status="Critical"))
|
||||
return report, reagent_map
|
||||
logger.debug(f"Here is the map coming out: {reagent_map}")
|
||||
return reagent_map
|
||||
|
||||
def parse_reagents(self) -> Generator[dict, None, None]:
|
||||
"""
|
||||
@@ -310,7 +312,7 @@ class ReagentParser(object):
|
||||
for sheet in self.xl.sheetnames:
|
||||
ws = self.xl[sheet]
|
||||
relevant = {k.strip(): v for k, v in self.map.items() if sheet in self.map[k]['sheet']}
|
||||
if relevant == {}:
|
||||
if not relevant:
|
||||
continue
|
||||
for item in relevant:
|
||||
try:
|
||||
|
||||
@@ -22,8 +22,8 @@ logger = logging.getLogger(f"submissions.{__name__}")
|
||||
class PydReagent(BaseModel):
|
||||
lot: str | None
|
||||
role: str | None
|
||||
expiry: date | Literal['NA'] | None
|
||||
name: str | None
|
||||
expiry: date | datetime | Literal['NA'] | None = Field(default=None, validate_default=True)
|
||||
name: str | None = Field(default=None, validate_default=True)
|
||||
missing: bool = Field(default=True)
|
||||
comment: str | None = Field(default="", validate_default=True)
|
||||
|
||||
@@ -79,6 +79,8 @@ class PydReagent(BaseModel):
|
||||
case str():
|
||||
return parse(value)
|
||||
case date():
|
||||
return datetime.combine(value, datetime.max.time())
|
||||
case datetime():
|
||||
return value
|
||||
case _:
|
||||
return convert_nans_to_nones(str(value))
|
||||
@@ -939,6 +941,7 @@ class PydSubmission(BaseModel, extra='allow'):
|
||||
ext_kit.get_reagents(required=True, submission_type=self.submission_type['value'])]
|
||||
# NOTE: Exclude any reagenttype found in this pyd not expected in kit.
|
||||
expected_check = [item.role for item in ext_kit_rtypes]
|
||||
logger.debug(self.reagents)
|
||||
output_reagents = [rt for rt in self.reagents if rt.role in expected_check]
|
||||
missing_check = [item.role for item in output_reagents]
|
||||
missing_reagents = [rt for rt in ext_kit_rtypes if rt.role not in missing_check and rt.role not in exempt]
|
||||
@@ -956,7 +959,7 @@ class PydSubmission(BaseModel, extra='allow'):
|
||||
report.add_result(result)
|
||||
return output_reagents, report, missing_reagents
|
||||
|
||||
def check_reagent_expiries(self, exempt: List[PydReagent]=[]):
|
||||
def check_reagent_expiries(self, exempt: List[PydReagent] = []):
|
||||
report = Report()
|
||||
expired = []
|
||||
for reagent in self.reagents:
|
||||
@@ -971,14 +974,11 @@ class PydSubmission(BaseModel, extra='allow'):
|
||||
if expired:
|
||||
output = '\n'.join(expired)
|
||||
result = Result(status="Warning",
|
||||
msg = f"The following reagents are expired:\n\n{output}"
|
||||
msg=f"The following reagents are expired:\n\n{output}"
|
||||
)
|
||||
report.add_result(result)
|
||||
return report
|
||||
|
||||
|
||||
|
||||
|
||||
def export_csv(self, filename: Path | str):
|
||||
try:
|
||||
worksheet = self.csv
|
||||
@@ -1009,14 +1009,34 @@ class PydContact(BaseModel):
|
||||
logger.debug(f"Output phone: {value}")
|
||||
return value
|
||||
|
||||
def toSQL(self) -> Contact:
|
||||
def toSQL(self) -> Tuple[Contact, Report]:
|
||||
"""
|
||||
Converts this instance into a backend.db.models.organization.Contact instance
|
||||
Converts this instance into a backend.db.models.organization. Contact instance.
|
||||
Does not query for existing contacts.
|
||||
|
||||
Returns:
|
||||
Contact: Contact instance
|
||||
"""
|
||||
return Contact(name=self.name, phone=self.phone, email=self.email)
|
||||
report = Report()
|
||||
instance = Contact.query(name=self.name, phone=self.phone, email=self.email)
|
||||
if not instance or isinstance(instance, list):
|
||||
instance = Contact()
|
||||
try:
|
||||
all_fields = self.model_fields + self.model_extra
|
||||
except TypeError:
|
||||
all_fields = self.model_fields
|
||||
for field in all_fields:
|
||||
value = getattr(self, field)
|
||||
match field:
|
||||
case "organization":
|
||||
value = [Organization.query(name=value)]
|
||||
case _:
|
||||
pass
|
||||
try:
|
||||
instance.__setattr__(field, value)
|
||||
except AttributeError as e:
|
||||
logger.error(f"Could not set {instance} {field} to {value} due to {e}")
|
||||
return instance, report
|
||||
|
||||
|
||||
class PydOrganization(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user