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) position = Column(Integer) # Matches `position` in data creation script data_collection_parameters = Column(JSON, nullable=True) # Foreign keys and relationships 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")