Update tell position logic and add new endpoint
Refactored tell position logic to use `segment` and `puck_in_segment` fields, replacing the previous single `tell_position` field. Introduced a new `/set-tell-positions` endpoint for setting tell positions based on these changes and removed the deprecated endpoint handling the old logic. Enhanced validation and streamlined handling of related logistics and puck events.
This commit is contained in:
parent
deeee02211
commit
14eaca81c6
@ -6,7 +6,6 @@ from app.schemas import (
|
||||
Puck as PuckSchema,
|
||||
PuckCreate,
|
||||
PuckUpdate,
|
||||
SetTellPosition,
|
||||
)
|
||||
from app.models import (
|
||||
Puck as PuckModel,
|
||||
@ -17,7 +16,6 @@ from app.models import (
|
||||
Dewar as DewarModel,
|
||||
)
|
||||
from app.dependencies import get_db
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
router = APIRouter()
|
||||
@ -81,6 +79,121 @@ async def get_pucks_with_tell_position(db: Session = Depends(get_db)):
|
||||
return result
|
||||
|
||||
|
||||
@router.put("/set-tell-positions", status_code=status.HTTP_200_OK)
|
||||
async def set_tell_positions(
|
||||
puck_name: str,
|
||||
segment: str,
|
||||
puck_in_segment: int,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Set the tell position for a puck based on the last beamline event.
|
||||
- Validates `puck_name`, `segment`, and `puck_in_segment`.
|
||||
- Finds the most recent logistics event of type "beamline" for the associated dewar.
|
||||
- Ensures the logistics event is associated with a valid slot.
|
||||
- Creates a new puck event with the specified `tell_position`.
|
||||
|
||||
Args:
|
||||
puck_name (str): Name of the puck to set the tell position for.
|
||||
segment (str): Segment label (A-F).
|
||||
puck_in_segment (int): Position in the segment (1-5).
|
||||
|
||||
Returns:
|
||||
JSON response containing puck and associated information.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# 1. Validate `segment` and `puck_in_segment`
|
||||
if not segment or segment not in "ABCDEF":
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Invalid segment. Valid segments are A, B, C, D, E, F.",
|
||||
)
|
||||
if not (1 <= puck_in_segment <= 5):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Invalid puck_in_segment. Valid positions are 1 to 5.",
|
||||
)
|
||||
|
||||
# Generate tell_position
|
||||
tell_position = f"{segment}{puck_in_segment}"
|
||||
|
||||
# 2. Find the puck by its name and ensure it exists
|
||||
puck = db.query(PuckModel).filter(PuckModel.puck_name == puck_name).first()
|
||||
if not puck:
|
||||
print(f"DEBUG: Puck '{puck_name}' not found in the database.")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
# This should match the error returned
|
||||
detail=f"Puck with name '{puck_name}' not found.",
|
||||
)
|
||||
print(f"DEBUG: Found puck: {puck}")
|
||||
|
||||
# 3. Find the dewar associated with the puck
|
||||
dewar = db.query(DewarModel).filter(DewarModel.id == puck.dewar_id).first()
|
||||
if not dewar:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Dewar associated with puck '{puck_name}' not found.",
|
||||
)
|
||||
|
||||
# 4. Find the most recent logistics event for the dewar (type 'beamline')
|
||||
# and ensure not null
|
||||
logistics_event = (
|
||||
db.query(LogisticsEventModel)
|
||||
.filter(
|
||||
LogisticsEventModel.dewar_id == dewar.id,
|
||||
LogisticsEventModel.event_type == "beamline",
|
||||
)
|
||||
.order_by(LogisticsEventModel.timestamp.desc())
|
||||
.first()
|
||||
)
|
||||
if not logistics_event:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=(
|
||||
f"No recent 'beamline' logistics event found for dewar '"
|
||||
f"{dewar.dewar_name}' "
|
||||
f"(puck '{puck_name}')."
|
||||
),
|
||||
)
|
||||
|
||||
# 5. Retrieve the slot from the logistics event
|
||||
slot = db.query(SlotModel).filter(SlotModel.id == logistics_event.slot_id).first()
|
||||
if not slot:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=(
|
||||
f"No slot associated with the most recent 'beamline' logistics event "
|
||||
f"for dewar '{dewar.dewar_name}'."
|
||||
),
|
||||
)
|
||||
|
||||
# 6. Set the tell position for the puck by creating a PuckEvent
|
||||
new_puck_event = PuckEventModel(
|
||||
puck_id=puck.id,
|
||||
tell_position=tell_position,
|
||||
event_type="tell_position_set",
|
||||
timestamp=datetime.utcnow(),
|
||||
)
|
||||
db.add(new_puck_event)
|
||||
db.commit()
|
||||
db.refresh(new_puck_event)
|
||||
|
||||
# 7. Return the result
|
||||
return {
|
||||
"puck_id": puck.id,
|
||||
"puck_name": puck_name,
|
||||
"dewar_id": dewar.id,
|
||||
"dewar_name": dewar.dewar_name,
|
||||
"slot_id": slot.id,
|
||||
"slot_label": slot.label,
|
||||
"tell_position": tell_position,
|
||||
"event_timestamp": new_puck_event.timestamp,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{puck_id}", response_model=PuckSchema)
|
||||
async def get_puck(puck_id: str, db: Session = Depends(get_db)):
|
||||
puck = db.query(PuckModel).filter(PuckModel.id == puck_id).first()
|
||||
@ -132,49 +245,6 @@ async def delete_puck(puck_id: str, db: Session = Depends(get_db)):
|
||||
return
|
||||
|
||||
|
||||
@router.put("/{puck_id}/tell_position", status_code=status.HTTP_200_OK)
|
||||
async def set_tell_position(
|
||||
puck_id: int, request: SetTellPosition, db: Session = Depends(get_db)
|
||||
):
|
||||
# Get the requested tell_position
|
||||
tell_position = request.tell_position
|
||||
|
||||
# Define valid positions
|
||||
valid_positions = [
|
||||
f"{letter}{num}" for letter in "ABCDEF" for num in range(1, 6)
|
||||
] + ["null", None]
|
||||
|
||||
# Validate tell_position
|
||||
if tell_position not in valid_positions:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"Invalid tell_position value. Must be one of {valid_positions}.",
|
||||
)
|
||||
|
||||
# Set the correct tell_position logic
|
||||
actual_position = None if tell_position in ["null", None] else tell_position
|
||||
|
||||
# Create a new PuckEvent (always a new event, even with null/None)
|
||||
new_puck_event = PuckEventModel(
|
||||
puck_id=puck_id,
|
||||
tell_position=actual_position,
|
||||
# Null for disassociation, else the valid position
|
||||
event_type="tell_position_set",
|
||||
# Example event type
|
||||
timestamp=datetime.utcnow(),
|
||||
)
|
||||
db.add(new_puck_event)
|
||||
db.commit()
|
||||
db.refresh(new_puck_event)
|
||||
|
||||
# Send the response
|
||||
return {
|
||||
"message": "New tell position event created successfully",
|
||||
"tell_position": new_puck_event.tell_position,
|
||||
"timestamp": new_puck_event.timestamp,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{puck_id}/last-tell-position", status_code=status.HTTP_200_OK)
|
||||
async def get_last_tell_position(puck_id: str, db: Session = Depends(get_db)):
|
||||
# Query the most recent tell_position_set event for the given puck_id
|
||||
|
@ -338,8 +338,27 @@ class SlotSchema(BaseModel):
|
||||
|
||||
|
||||
class SetTellPosition(BaseModel):
|
||||
tell_position: str = Field(
|
||||
...,
|
||||
pattern="^[A-F][1-5]$|^null$|^None$", # Use 'pattern' instead of 'regex'
|
||||
description="Valid values are A1-A5, B1-B5, ..., F1-F5, or null.",
|
||||
puckname: str # The puck name is required.
|
||||
segment: Optional[str] = Field(
|
||||
None,
|
||||
pattern="^[A-F]$", # Valid segments are A, B, C, D, E, F
|
||||
description="Segment must be one of A, B, C, D, E, or F."
|
||||
"Can be null for no tell_position.",
|
||||
)
|
||||
puck_in_segment: Optional[int] = Field(
|
||||
None,
|
||||
ge=1,
|
||||
le=5,
|
||||
description="Puck in segment must be between 1 and 5."
|
||||
"Can be null for no tell_position.",
|
||||
)
|
||||
|
||||
@property
|
||||
def tell_position(self) -> Optional[str]:
|
||||
"""
|
||||
Combines `segment` and `puck_in_segment` to generate the `tell_position`.
|
||||
If either value is `None`, returns `None` to indicate no `tell_position`.
|
||||
"""
|
||||
if self.segment and self.puck_in_segment:
|
||||
return f"{self.segment}{self.puck_in_segment}"
|
||||
return None
|
||||
|
Loading…
x
Reference in New Issue
Block a user