Skip to content

Commit a636d62

Browse files
committed
Preserve Atlas order refs in beta material context
1 parent 3bb128b commit a636d62

3 files changed

Lines changed: 127 additions & 0 deletions

File tree

bloom_lims/domain/beta_lab_refs.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,21 @@ def _atlas_context_for_instance(self, instance) -> dict[str, Any]:
601601
reference_type=self.TRF_REFERENCE_TYPE,
602602
value_field="atlas_trf_euid",
603603
)
604+
atlas_order_euid = self._first_reachable_reference_value(
605+
instance,
606+
reference_type="order_euid",
607+
value_field="order_euid",
608+
)
609+
atlas_order_test_euid = self._first_reachable_reference_value(
610+
instance,
611+
reference_type="order_test_euid",
612+
value_field="order_test_euid",
613+
)
614+
direct_order_test_euids = self._reachable_reference_values(
615+
instance,
616+
reference_type="order_test_euid",
617+
value_field="order_test_euid",
618+
)
604619
atlas_test_euid = self._first_reachable_reference_value(
605620
instance,
606621
reference_type=self.TEST_REFERENCE_TYPE,
@@ -628,6 +643,16 @@ def _atlas_context_for_instance(self, instance) -> dict[str, Any]:
628643
)
629644
atlas_test_euids: list[str] = []
630645
seen_test_euids: set[str] = set()
646+
atlas_order_test_euids: list[str] = []
647+
seen_order_test_euids: set[str] = set()
648+
for direct_order_test_euid in direct_order_test_euids:
649+
if direct_order_test_euid in seen_order_test_euids:
650+
continue
651+
seen_order_test_euids.add(direct_order_test_euid)
652+
atlas_order_test_euids.append(direct_order_test_euid)
653+
if atlas_order_test_euid and atlas_order_test_euid not in seen_order_test_euids:
654+
seen_order_test_euids.add(atlas_order_test_euid)
655+
atlas_order_test_euids.append(atlas_order_test_euid)
631656
for direct_test_euid in direct_test_euids:
632657
if direct_test_euid in seen_test_euids:
633658
continue
@@ -656,6 +681,16 @@ def _atlas_context_for_instance(self, instance) -> dict[str, Any]:
656681
reference_type=self.TEST_REFERENCE_TYPE,
657682
value_field="atlas_tenant_id",
658683
)
684+
or self._first_reachable_reference_value(
685+
instance,
686+
reference_type="order_euid",
687+
value_field="atlas_tenant_id",
688+
)
689+
or self._first_reachable_reference_value(
690+
instance,
691+
reference_type="order_test_euid",
692+
value_field="atlas_tenant_id",
693+
)
659694
or self._first_reachable_reference_value(
660695
instance,
661696
reference_type=self.TESTKIT_REFERENCE_TYPE,
@@ -685,6 +720,9 @@ def _atlas_context_for_instance(self, instance) -> dict[str, Any]:
685720
if not fulfillment_items:
686721
return {
687722
"atlas_tenant_id": atlas_tenant_id,
723+
"atlas_order_euid": atlas_order_euid,
724+
"atlas_order_test_euid": atlas_order_test_euid,
725+
"atlas_order_test_euids": atlas_order_test_euids,
688726
"atlas_trf_euid": atlas_trf_euid,
689727
"atlas_test_euid": atlas_test_euid,
690728
"atlas_test_euids": atlas_test_euids,
@@ -709,6 +747,9 @@ def _atlas_context_for_instance(self, instance) -> dict[str, Any]:
709747
first = fulfillment_items[0]
710748
return {
711749
"atlas_tenant_id": first["atlas_tenant_id"],
750+
"atlas_order_euid": atlas_order_euid,
751+
"atlas_order_test_euid": atlas_order_test_euid,
752+
"atlas_order_test_euids": atlas_order_test_euids,
712753
"atlas_trf_euid": first["atlas_trf_euid"] or atlas_trf_euid,
713754
"atlas_test_euid": atlas_test_euid or first["atlas_test_euid"],
714755
"atlas_test_euids": atlas_test_euids,

bloom_lims/schemas/beta_lab.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
class AtlasFulfillmentItemReference(BaseModel):
2727
atlas_test_euid: str
2828
atlas_test_fulfillment_item_euid: str
29+
atlas_order_test_euid: str | None = None
30+
31+
32+
class AtlasFulfillmentSlotReference(BaseModel):
33+
atlas_order_test_euid: str
34+
atlas_fulfillment_slot_euid: str
2935

3036

3137
class AtlasCollectionEventSnapshot(BaseModel):
@@ -42,6 +48,9 @@ class AtlasCollectionEventSnapshot(BaseModel):
4248

4349
class AtlasFulfillmentContext(BaseModel):
4450
atlas_tenant_id: str
51+
atlas_order_euid: str | None = None
52+
atlas_order_test_euid: str | None = None
53+
atlas_order_test_euids: list[str] = Field(default_factory=list)
4554
atlas_trf_euid: str | None = None
4655
atlas_test_euid: str | None = None
4756
atlas_test_euids: list[str] = Field(default_factory=list)
@@ -52,13 +61,50 @@ class AtlasFulfillmentContext(BaseModel):
5261
atlas_collection_event_euid: str | None = None
5362
collection_event_snapshot: AtlasCollectionEventSnapshot | None = None
5463
fulfillment_items: list[AtlasFulfillmentItemReference] = Field(default_factory=list)
64+
fulfillment_slots: list[AtlasFulfillmentSlotReference] = Field(default_factory=list)
5565

5666
@model_validator(mode="after")
5767
def validate_context(self) -> "AtlasFulfillmentContext":
5868
if not self.atlas_tenant_id.strip():
5969
raise ValueError("atlas_tenant_id is required")
6070
if self.atlas_trf_euid is not None and not self.atlas_trf_euid.strip():
6171
raise ValueError("atlas_trf_euid must not be empty when provided")
72+
if self.atlas_order_euid is not None and not self.atlas_order_euid.strip():
73+
raise ValueError("atlas_order_euid must not be empty when provided")
74+
if (
75+
self.atlas_order_test_euid is not None
76+
and not self.atlas_order_test_euid.strip()
77+
):
78+
raise ValueError("atlas_order_test_euid must not be empty when provided")
79+
normalized_order_test_euids: list[str] = []
80+
seen_order_test_euids: set[str] = set()
81+
primary_order_test_euid = str(self.atlas_order_test_euid or "").strip()
82+
if primary_order_test_euid:
83+
seen_order_test_euids.add(primary_order_test_euid)
84+
normalized_order_test_euids.append(primary_order_test_euid)
85+
for item in self.atlas_order_test_euids:
86+
clean_item = str(item or "").strip()
87+
if not clean_item or clean_item in seen_order_test_euids:
88+
continue
89+
seen_order_test_euids.add(clean_item)
90+
normalized_order_test_euids.append(clean_item)
91+
for item in self.fulfillment_slots:
92+
clean_item = str(item.atlas_order_test_euid or "").strip()
93+
if clean_item and clean_item not in seen_order_test_euids:
94+
seen_order_test_euids.add(clean_item)
95+
normalized_order_test_euids.append(clean_item)
96+
for item in self.fulfillment_items:
97+
clean_item = str(item.atlas_order_test_euid or "").strip()
98+
if clean_item and clean_item not in seen_order_test_euids:
99+
seen_order_test_euids.add(clean_item)
100+
normalized_order_test_euids.append(clean_item)
101+
self.atlas_order_test_euids = normalized_order_test_euids
102+
if self.atlas_order_test_euid is None and self.atlas_order_test_euids:
103+
self.atlas_order_test_euid = self.atlas_order_test_euids[0]
104+
if (self.atlas_order_test_euid or self.atlas_order_test_euids) and not self.atlas_order_euid:
105+
raise ValueError(
106+
"atlas_order_euid is required when atlas_order_test_euid is provided"
107+
)
62108
if self.atlas_test_euid is not None and not self.atlas_test_euid.strip():
63109
raise ValueError("atlas_test_euid must not be empty when provided")
64110
normalized_test_euids: list[str] = []

tests/test_beta_lab_schema.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Schema regressions for Bloom beta lab payload contracts."""
2+
3+
from __future__ import annotations
4+
5+
import pytest
6+
7+
from bloom_lims.schemas.beta_lab import AtlasFulfillmentContext
8+
9+
10+
def test_atlas_fulfillment_context_preserves_order_refs():
11+
context = AtlasFulfillmentContext(
12+
atlas_tenant_id="tenant-1",
13+
atlas_order_euid="Z-AGX-ORDER1",
14+
atlas_order_test_euid="Z-AGX-TEST1",
15+
atlas_order_test_euids=["Z-AGX-TEST1", "Z-AGX-TEST2"],
16+
fulfillment_slots=[
17+
{
18+
"atlas_order_test_euid": "Z-AGX-TEST2",
19+
"atlas_fulfillment_slot_euid": "Z-AGX-SLOT1",
20+
}
21+
],
22+
)
23+
24+
payload = context.model_dump()
25+
26+
assert payload["atlas_order_euid"] == "Z-AGX-ORDER1"
27+
assert payload["atlas_order_test_euid"] == "Z-AGX-TEST1"
28+
assert payload["atlas_order_test_euids"] == [
29+
"Z-AGX-TEST1",
30+
"Z-AGX-TEST2",
31+
]
32+
assert payload["fulfillment_slots"][0]["atlas_fulfillment_slot_euid"] == "Z-AGX-SLOT1"
33+
34+
35+
def test_atlas_fulfillment_context_requires_order_for_order_tests():
36+
with pytest.raises(ValueError, match="atlas_order_euid is required"):
37+
AtlasFulfillmentContext(
38+
atlas_tenant_id="tenant-1",
39+
atlas_order_test_euid="Z-AGX-TEST1",
40+
)

0 commit comments

Comments
 (0)