Skip to content

Commit 5861cb3

Browse files
committed
Complete Bloom lab-action live proof support
1 parent 0d57f0a commit 5861cb3

4 files changed

Lines changed: 93 additions & 4 deletions

File tree

bloom_lims/domain/lab_actions.py

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
POOL_CONTENT_TEMPLATE_CODE = "content/pool/sequencing-library/1.0/"
4747
GDNA_QUANT_TEMPLATE_CODE = "data/quantification/gdna/1.0/"
4848
EXTRACTION_QC_TEMPLATE_CODE = "data/operation/extraction-qc/1.0/"
49+
SEQUENCED_LIBRARY_ASSIGNMENT_TEMPLATE_CODE = (
50+
"data/library-index-assignment/sequencing-library/1.0/"
51+
)
4952

5053

5154
def re_split_multi(value: str) -> list[str]:
@@ -795,15 +798,77 @@ def create_seq_run_set(self, request: SeqRunSetRequest) -> dict[str, Any]:
795798
self._create_lineage(run_set.euid, request.instrument_euid, "run_uses_instrument")
796799
for reagent_euid in request.reagent_euids:
797800
self._create_lineage(run_set.euid, reagent_euid, "run_uses_reagent")
801+
assignments = self._create_sequenced_library_assignments(
802+
run_set=run_set,
803+
pool_content=pool_content,
804+
flowcell_barcode=request.flowcell_barcode,
805+
)
798806
self.bdb.session.commit()
799807
return {
800808
"set_euid": run_set.euid,
801809
"status": run_set.bstatus,
802810
"platform": request.platform,
803811
"pool_tube_euid": pool_tube.euid,
804812
"pool_content_euid": pool_content.euid,
813+
"assignments": assignments,
805814
}
806815

816+
def _create_sequenced_library_assignments(
817+
self,
818+
*,
819+
run_set,
820+
pool_content,
821+
flowcell_barcode: str,
822+
) -> list[dict[str, str]]:
823+
assignments: list[dict[str, str]] = []
824+
source_libraries = [
825+
lineage.parent_instance
826+
for lineage in self._lineages_to_child(pool_content, "DERIVED_FROM")
827+
]
828+
for index, library in enumerate(source_libraries, start=1):
829+
props = self._props(library)
830+
barcode = str(props.get("index_barcode") or "").strip()
831+
lane = str(props.get("lane") or props.get("lane_index") or "1").strip()
832+
assignment = self._create_by_code(
833+
SEQUENCED_LIBRARY_ASSIGNMENT_TEMPLATE_CODE,
834+
name=f"{run_set.euid}:{lane}:{barcode or library.euid}",
835+
properties={
836+
"flowcell_id": flowcell_barcode,
837+
"lane": lane,
838+
"library_barcode": barcode,
839+
"library_prep_output_euid": library.euid,
840+
"library_material_euid": library.euid,
841+
"barcode_reagent_euid": str(props.get("index_euid") or "").strip(),
842+
"metadata": {
843+
"created_by": "bloom_lab_actions",
844+
"pool_content_euid": pool_content.euid,
845+
},
846+
},
847+
)
848+
self._create_lineage(
849+
run_set.euid,
850+
assignment.euid,
851+
"beta_sequenced_library_assignment",
852+
)
853+
self._create_lineage(
854+
library.euid,
855+
assignment.euid,
856+
"beta_assignment_source",
857+
edge_type="RUN_CONSUMED",
858+
source_role="sequencing_run_set",
859+
target_role="library_material",
860+
)
861+
assignments.append(
862+
{
863+
"assignment_euid": assignment.euid,
864+
"library_content_euid": library.euid,
865+
"flowcell_id": flowcell_barcode,
866+
"lane": lane,
867+
"library_barcode": barcode,
868+
}
869+
)
870+
return assignments
871+
807872
def plate_mapping_rows(self, plate_euid: str) -> list[dict[str, str]]:
808873
plate = self._require(plate_euid)
809874
wells = self._plate_wells(plate)
@@ -1302,10 +1367,22 @@ def import_spreadsheet(
13021367
return {"filename": filename, "dry_run": dry_run, "actions": actions}
13031368

13041369
def print_euids(self, request: PrintEuidRequest) -> dict[str, Any]:
1305-
service = ZebraDayService()
13061370
results = []
13071371
for euid in request.euids:
13081372
self._require(euid)
1373+
if request.dry_run:
1374+
results.append(
1375+
{
1376+
"dry_run": True,
1377+
"lab": request.lab,
1378+
"printer_id": request.printer_id,
1379+
"label_zpl_style": request.label_zpl_style,
1380+
"euid": euid,
1381+
"copies": request.copies,
1382+
}
1383+
)
1384+
continue
1385+
service = ZebraDayService()
13091386
results.append(
13101387
service.submit_print_job(
13111388
lab=request.lab,
@@ -1315,4 +1392,4 @@ def print_euids(self, request: PrintEuidRequest) -> dict[str, Any]:
13151392
print_n=request.copies,
13161393
)
13171394
)
1318-
return {"printed": len(results), "results": results}
1395+
return {"printed": 0 if request.dry_run else len(results), "dry_run": request.dry_run, "results": results}

bloom_lims/schemas/lab_actions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ class PrintEuidRequest(BaseModel):
260260
printer_id: str
261261
label_zpl_style: str
262262
copies: int = Field(default=1, ge=1, le=20)
263+
dry_run: bool = False
263264

264265
@field_validator("euids")
265266
@classmethod

templates/modern/lab_actions.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ <h2>Print EUID Barcodes</h2>
240240
<input id="print-style" class="form-control" data-testid="bloom-lab-print-style" value="euid">
241241
</div>
242242
</div>
243+
<label class="checkbox-row">
244+
<input type="checkbox" id="print-dry-run" data-testid="bloom-lab-print-dry-run" checked>
245+
Preview only; do not send to printer
246+
</label>
243247
<button class="btn btn-outline" type="button" data-action="print-euids" data-testid="bloom-lab-print-submit">
244248
<i class="fas fa-barcode"></i> Print Selected EUIDs
245249
</button>
@@ -468,6 +472,7 @@ <h2>Action Results</h2>
468472
printer_id: document.getElementById('print-printer').value.trim(),
469473
label_zpl_style: document.getElementById('print-style').value.trim(),
470474
copies: 1,
475+
dry_run: document.getElementById('print-dry-run').checked,
471476
}),
472477
};
473478

tests/test_lab_actions_api.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ def test_lab_actions_full_ilmn_flow_and_csv_export() -> None:
201201
assert seq_run.status_code == 200, seq_run.text
202202
run_payload = seq_run.json()
203203
assert run_payload["set_euid"]
204+
assert run_payload["assignments"]
205+
assert run_payload["assignments"][0]["flowcell_id"] == "PYTEST-FLOWCELL"
206+
assert run_payload["assignments"][0]["lane"] == "1"
204207

205208
sample_sheet = client.get(
206209
f"/api/v1/lab-actions/seq-runs/{run_payload['set_euid']}/samplesheet"
@@ -282,11 +285,14 @@ def test_object_creation_count_and_print_euid_mock() -> None:
282285
"printer_id": "pytest-printer",
283286
"label_zpl_style": "euid",
284287
"copies": 1,
288+
"dry_run": True,
285289
},
286290
)
287291
assert response.status_code == 200, response.text
288-
assert response.json()["printed"] == 3
289-
assert service.submit_print_job.call_count == 3
292+
assert response.json()["printed"] == 0
293+
assert response.json()["dry_run"] is True
294+
assert service.submit_print_job.call_count == 0
295+
assert len(response.json()["results"]) == 3
290296

291297
recursive_batch = client.post(
292298
"/api/v1/object-creation/create",

0 commit comments

Comments
 (0)