
Introduced `mount_count` and `unmount_count` fields to track mounting events for samples. Updated models, schemas, and front-end components to support dynamic calculation and display of these counts. Enhanced backend queries and API responses to include the new data.
212 lines
7.4 KiB
Python
212 lines
7.4 KiB
Python
from sqlalchemy import (
|
|
Column,
|
|
Integer,
|
|
String,
|
|
Date,
|
|
ForeignKey,
|
|
JSON,
|
|
DateTime,
|
|
Boolean,
|
|
)
|
|
from sqlalchemy.orm import relationship
|
|
from .database import Base
|
|
from datetime import datetime
|
|
|
|
|
|
class Shipment(Base):
|
|
__tablename__ = "shipments"
|
|
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
shipment_name = Column(String(255), index=True)
|
|
shipment_date = Column(Date)
|
|
shipment_status = Column(String(255))
|
|
comments = Column(String(200), nullable=True)
|
|
contact_person_id = Column(Integer, ForeignKey("contact_persons.id"))
|
|
return_address_id = Column(Integer, ForeignKey("addresses.id"))
|
|
proposal_id = Column(Integer, ForeignKey("proposals.id"), nullable=True)
|
|
|
|
contact_person = relationship("ContactPerson", back_populates="shipments")
|
|
return_address = relationship("Address", back_populates="shipments")
|
|
proposal = relationship("Proposal", back_populates="shipments")
|
|
dewars = relationship("Dewar", back_populates="shipment")
|
|
|
|
|
|
class ContactPerson(Base):
|
|
__tablename__ = "contact_persons"
|
|
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
firstname = Column(String(255))
|
|
lastname = Column(String(255))
|
|
phone_number = Column(String(255))
|
|
email = Column(String(255))
|
|
shipments = relationship("Shipment", back_populates="contact_person")
|
|
|
|
|
|
class Address(Base):
|
|
__tablename__ = "addresses"
|
|
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
street = Column(String(255))
|
|
city = Column(String(255))
|
|
zipcode = Column(String(255))
|
|
country = Column(String(255))
|
|
|
|
shipments = relationship("Shipment", back_populates="return_address")
|
|
|
|
|
|
class DewarType(Base):
|
|
__tablename__ = "dewar_types"
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
dewar_type = Column(String(255), unique=True, index=True)
|
|
serial_numbers = relationship("DewarSerialNumber", back_populates="dewar_type")
|
|
|
|
|
|
class DewarSerialNumber(Base):
|
|
__tablename__ = "dewar_serial_numbers"
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
serial_number = Column(String(255), index=True)
|
|
dewar_type_id = Column(Integer, ForeignKey("dewar_types.id"))
|
|
dewar_type = relationship("DewarType", back_populates="serial_numbers")
|
|
|
|
|
|
class Dewar(Base):
|
|
__tablename__ = "dewars"
|
|
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
dewar_name = Column(String(255))
|
|
dewar_type_id = Column(Integer, ForeignKey("dewar_types.id"), nullable=True)
|
|
dewar_serial_number_id = Column(
|
|
Integer, ForeignKey("dewar_serial_numbers.id"), nullable=True
|
|
)
|
|
tracking_number = Column(String(255))
|
|
status = Column(String(255))
|
|
ready_date = Column(Date, nullable=True)
|
|
shipping_date = Column(Date, nullable=True)
|
|
arrival_date = Column(Date, nullable=True)
|
|
returning_date = Column(Date, nullable=True)
|
|
unique_id = Column(String(255), unique=True, index=True, nullable=True)
|
|
shipment_id = Column(Integer, ForeignKey("shipments.id"))
|
|
return_address_id = Column(Integer, ForeignKey("addresses.id"))
|
|
contact_person_id = Column(Integer, ForeignKey("contact_persons.id"))
|
|
|
|
shipment = relationship("Shipment", back_populates="dewars")
|
|
return_address = relationship("Address")
|
|
contact_person = relationship("ContactPerson")
|
|
pucks = relationship("Puck", back_populates="dewar")
|
|
|
|
dewar_type = relationship("DewarType")
|
|
dewar_serial_number = relationship("DewarSerialNumber")
|
|
slot = relationship("Slot", back_populates="dewar")
|
|
events = relationship("LogisticsEvent", back_populates="dewar")
|
|
beamline_location = None
|
|
|
|
@property
|
|
def number_of_pucks(self) -> int:
|
|
return len(self.pucks) if self.pucks else 0
|
|
|
|
@property
|
|
def number_of_samples(self) -> int:
|
|
if not self.pucks:
|
|
return 0
|
|
return sum(len(puck.samples) for puck in self.pucks)
|
|
|
|
|
|
class Proposal(Base):
|
|
__tablename__ = "proposals"
|
|
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
number = Column(String(255))
|
|
shipments = relationship("Shipment", back_populates="proposal")
|
|
|
|
|
|
class Puck(Base):
|
|
__tablename__ = "pucks"
|
|
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
puck_name = Column(String(255), index=True)
|
|
puck_type = Column(String(255))
|
|
puck_location_in_dewar = Column(Integer)
|
|
|
|
# Foreign keys and relationships
|
|
dewar_id = Column(Integer, ForeignKey("dewars.id"))
|
|
dewar = relationship("Dewar", back_populates="pucks")
|
|
samples = relationship("Sample", back_populates="puck")
|
|
events = relationship("PuckEvent", back_populates="puck")
|
|
|
|
|
|
class Sample(Base):
|
|
__tablename__ = "samples"
|
|
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
sample_name = Column(String(255), index=True)
|
|
proteinname = Column(String(255), index=True)
|
|
position = Column(Integer)
|
|
priority = Column(Integer)
|
|
comments = Column(String(255))
|
|
data_collection_parameters = Column(JSON, nullable=True)
|
|
|
|
# Foreign keys and relationships
|
|
dewar_id = Column(Integer, ForeignKey("dewars.id"))
|
|
puck_id = Column(Integer, ForeignKey("pucks.id"))
|
|
puck = relationship("Puck", back_populates="samples")
|
|
events = relationship("SampleEvent", back_populates="sample")
|
|
|
|
@property
|
|
def mount_count(self) -> int:
|
|
# Dynamically calculate mount_count
|
|
return len([event for event in self.events if event.event_type == "Mounted"])
|
|
|
|
@property
|
|
def unmount_count(self) -> int:
|
|
# Dynamically calculate unmount_count
|
|
return len([event for event in self.events if event.event_type == "Unmounted"])
|
|
|
|
|
|
class Slot(Base):
|
|
__tablename__ = "slots"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
qr_code = Column(String(255), unique=True, index=True)
|
|
label = Column(String(255))
|
|
qr_base = Column(String(255), nullable=True)
|
|
occupied = Column(Boolean, default=False)
|
|
needs_refill = Column(Boolean, default=False)
|
|
dewar_unique_id = Column(String(255), ForeignKey("dewars.unique_id"), nullable=True)
|
|
dewar = relationship("Dewar", back_populates="slot")
|
|
events = relationship("LogisticsEvent", back_populates="slot")
|
|
|
|
|
|
class LogisticsEvent(Base):
|
|
__tablename__ = "logistics_events"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
dewar_id = Column(Integer, ForeignKey("dewars.id"))
|
|
slot_id = Column(Integer, ForeignKey("slots.id"))
|
|
event_type = Column(String(255), index=True)
|
|
timestamp = Column(DateTime, default=datetime.utcnow)
|
|
dewar = relationship("Dewar", back_populates="events")
|
|
slot = relationship("Slot", back_populates="events")
|
|
|
|
|
|
class SampleEvent(Base):
|
|
__tablename__ = "sample_events"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
sample_id = Column(Integer, ForeignKey("samples.id"))
|
|
event_type = Column(String(255), index=True)
|
|
timestamp = Column(DateTime, default=datetime.utcnow)
|
|
|
|
sample = relationship("Sample", back_populates="events")
|
|
|
|
|
|
class PuckEvent(Base):
|
|
__tablename__ = "puck_events"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
puck_id = Column(Integer, ForeignKey("pucks.id"))
|
|
tell_position = Column(String(255), nullable=True)
|
|
event_type = Column(String(255), index=True)
|
|
timestamp = Column(DateTime, default=datetime.utcnow)
|
|
|
|
puck = relationship("Puck", back_populates="events")
|