54975b5919
Implemented a toggleable spreadsheet UI component for sample data, added fields such as priority and comments, and improved backend validation. Default values for "directory" are now assigned when missing, with feedback highlighted in green on the front end.
202 lines
7.0 KiB
Python
202 lines
7.0 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")
|
|
|
|
|
|
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")
|