now associating a dewar to a slot

This commit is contained in:
GotthardG 2024-11-19 13:43:54 +01:00
parent 48fd2c3a7c
commit fa1e9c86b8
4 changed files with 41 additions and 18 deletions

View File

@ -86,6 +86,7 @@ class Dewar(Base):
dewar_type = relationship("DewarType") dewar_type = relationship("DewarType")
dewar_serial_number = relationship("DewarSerialNumber") dewar_serial_number = relationship("DewarSerialNumber")
slot = relationship("Slot", back_populates="dewar")
@property @property
def number_of_pucks(self) -> int: def number_of_pucks(self) -> int:
@ -144,6 +145,9 @@ class Slot(Base):
needs_refill = Column(Boolean, default=False) needs_refill = Column(Boolean, default=False)
last_refill = Column(DateTime, default=datetime.utcnow) last_refill = Column(DateTime, default=datetime.utcnow)
time_until_refill = Column(Integer) # store as total seconds time_until_refill = Column(Integer) # store as total seconds
dewar_unique_id = Column(String, ForeignKey('dewars.unique_id'), nullable=True) # Added field
dewar = relationship("Dewar", back_populates="slot")
@property @property
def calculate_time_until_refill(self): def calculate_time_until_refill(self):
@ -151,6 +155,7 @@ class Slot(Base):
return self.last_refill + self.time_until_refill - datetime.utcnow() return self.last_refill + self.time_until_refill - datetime.utcnow()
return None return None
class LogisticsEvent(Base): class LogisticsEvent(Base):
__tablename__ = 'logistics_events' __tablename__ = 'logistics_events'
id = Column(Integer, primary_key=True, index=True, autoincrement=True) id = Column(Integer, primary_key=True, index=True, autoincrement=True)
@ -158,4 +163,5 @@ class LogisticsEvent(Base):
event_type = Column(String, nullable=False) event_type = Column(String, nullable=False)
timestamp = Column(DateTime, default=datetime.utcnow) timestamp = Column(DateTime, default=datetime.utcnow)
dewar = relationship("Dewar", back_populates="events") dewar = relationship("Dewar", back_populates="events")
slot_id = Column(String, ForeignKey('slots.id'), nullable=True)

View File

@ -1,22 +1,42 @@
from fastapi import APIRouter, HTTPException, Depends from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from datetime import datetime, timedelta
from typing import List from typing import List
from app.models import Dewar as DewarModel, Slot as SlotModel, LogisticsEvent as LogisticsEventModel from app.models import Dewar as DewarModel, Slot as SlotModel, LogisticsEvent as LogisticsEventModel
from app.schemas import LogisticsEventCreate, Slot as SlotSchema, Dewar as DewarSchema from app.schemas import LogisticsEventCreate, Slot as SlotSchema, Dewar as DewarSchema
from app.database import get_db from app.database import get_db
import logging import logging
from datetime import datetime, timedelta
router = APIRouter() router = APIRouter()
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def calculate_time_until_refill(last_refill: datetime) -> int:
refill_interval = timedelta(hours=24) # Example interval
now = datetime.now()
time_until_next_refill = last_refill + refill_interval - now
return int(time_until_next_refill.total_seconds())
@router.get("/slots", response_model=List[SlotSchema]) @router.get("/slots", response_model=List[SlotSchema])
async def get_all_slots(db: Session = Depends(get_db)): async def get_all_slots(db: Session = Depends(get_db)):
slots = db.query(SlotModel).all() slots = db.query(SlotModel).all()
return slots slots_with_refill_time = []
for slot in slots:
slot_data = SlotSchema(
id=slot.id,
qr_code=slot.qr_code,
label=slot.label,
qr_base=slot.qr_base,
occupied=slot.occupied,
needs_refill=slot.needs_refill,
last_refill=slot.last_refill,
time_until_refill=calculate_time_until_refill(slot.last_refill),
dewar_unique_id=slot.dewar_unique_id,
dewar_name=slot.dewar.dewar_name if slot.dewar else None
)
slots_with_refill_time.append(slot_data)
return slots_with_refill_time
@router.get("/dewars", response_model=List[DewarSchema]) @router.get("/dewars", response_model=List[DewarSchema])
async def get_all_dewars(db: Session = Depends(get_db)): async def get_all_dewars(db: Session = Depends(get_db)):
@ -39,20 +59,25 @@ async def scan_dewar(event_data: LogisticsEventCreate, db: Session = Depends(get
location_qr_code = event_data.location_qr_code location_qr_code = event_data.location_qr_code
transaction_type = event_data.transaction_type transaction_type = event_data.transaction_type
print(f"Scanning dewar {dewar_qr_code} for slot {location_qr_code} with transaction type {transaction_type}")
dewar = db.query(DewarModel).filter(DewarModel.unique_id == dewar_qr_code).first() dewar = db.query(DewarModel).filter(DewarModel.unique_id == dewar_qr_code).first()
if not dewar: if not dewar:
raise HTTPException(status_code=404, detail="Dewar not found") raise HTTPException(status_code=404, detail="Dewar not found")
slot = db.query(SlotModel).filter(SlotModel.qr_code == location_qr_code).first() slot = db.query(SlotModel).filter(SlotModel.qr_code == location_qr_code).first()
if transaction_type == 'incoming': if transaction_type == 'incoming':
if not slot or slot.occupied: if not slot or slot.occupied:
raise HTTPException(status_code=400, detail="Slot not found or already occupied") raise HTTPException(status_code=400, detail="Slot not found or already occupied")
slot.dewar_id = dewar.id print(f"Associating dewar {dewar.unique_id} with slot {slot.qr_code}")
slot.dewar_unique_id = dewar.unique_id # Properly associate with the unique_id
slot.occupied = True slot.occupied = True
elif transaction_type == 'outgoing': elif transaction_type == 'outgoing':
if not slot or not slot.occupied or slot.dewar_id != dewar.id: if not slot or not slot.occupied or slot.dewar_unique_id != dewar.unique_id:
raise HTTPException(status_code=400, detail="Slot not found or dewar not associated with slot") raise HTTPException(status_code=400, detail="Slot not found or dewar not associated with slot")
slot.dewar_id = None print(f"Disassociating dewar {dewar.unique_id} from slot {slot.qr_code}")
slot.dewar_unique_id = None # Remove the association
slot.occupied = False slot.occupied = False
log_event(db, dewar.id, slot.id if slot else None, transaction_type) log_event(db, dewar.id, slot.id if slot else None, transaction_type)

View File

@ -281,11 +281,13 @@ class Slot(BaseModel):
id: str id: str
qr_code: str qr_code: str
label: str label: str
qr_base: str qr_base: Optional[str]
occupied: bool occupied: bool
needs_refill: bool needs_refill: bool
last_refill: datetime last_refill: datetime
time_until_refill: str time_until_refill: int # Can't be Optional
dewar_unique_id: Optional[str] # Ensure this field exists
dewar_name: Optional[str] = None # Optional for convenience
class Config: class Config:
from_attributes = True from_attributes = True

View File

@ -31,16 +31,11 @@ interface StorageProps {
} }
const Storage: React.FC<StorageProps> = ({ name, selectedSlot, slotsData, onSelectSlot }) => { const Storage: React.FC<StorageProps> = ({ name, selectedSlot, slotsData, onSelectSlot }) => {
const [highlightedSlot, setHighlightedSlot] = useState<SlotData | null>(null);
const handleSlotSelect = (slot: SlotData) => { const handleSlotSelect = (slot: SlotData) => {
setHighlightedSlot(slot);
onSelectSlot(slot); onSelectSlot(slot);
console.log('Selected slot:', slot); console.log('Selected slot:', slot);
}; };
console.log("Rendering Storage Component with name:", name);
return ( return (
<StorageContainer> <StorageContainer>
<Typography variant="h5">{name} Slots</Typography> <Typography variant="h5">{name} Slots</Typography>
@ -54,11 +49,6 @@ const Storage: React.FC<StorageProps> = ({ name, selectedSlot, slotsData, onSele
/> />
))} ))}
</StorageWrapper> </StorageWrapper>
{highlightedSlot && (
<Typography variant="subtitle1">
Selected Slot: {highlightedSlot.label}
</Typography>
)}
</StorageContainer> </StorageContainer>
); );
}; };