from sqlalchemy import Column, Integer, String, Date, ForeignKey, JSON, Interval, DateTime, Boolean from sqlalchemy.orm import relationship from app.database import Base from datetime import datetime, timedelta import uuid class Shipment(Base): __tablename__ = "shipments" id = Column(Integer, primary_key=True, index=True, autoincrement=True) shipment_name = Column(String, index=True) shipment_date = Column(Date) shipment_status = Column(String) 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) lastname = Column(String) phone_number = Column(String) email = Column(String) 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) city = Column(String) zipcode = Column(String) country = Column(String) 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, 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, 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) 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) status = Column(String) 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, 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") @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) 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, index=True) puck_type = Column(String) 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") class Sample(Base): __tablename__ = 'samples' id = Column(Integer, primary_key=True, index=True, autoincrement=True) sample_name = Column(String, index=True) # Matches `sample_name` in data creation 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") class Slot(Base): __tablename__ = "slots" id = Column(String, primary_key=True, index=True) qr_code = Column(String, unique=True, index=True) label = Column(String) qr_base = Column(String, nullable=True) occupied = Column(Boolean, default=False) needs_refill = Column(Boolean, default=False) dewar_name = Column(String) # Ensure this field exists dewar_unique_id = Column(String, ForeignKey('dewars.unique_id'), nullable=True) # Added field 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')) # corrected table name slot_id = Column(Integer, ForeignKey('slots.id')) # corrected table name event_type = Column(String, index=True) timestamp = Column(DateTime, default=datetime.utcnow) dewar = relationship("Dewar", back_populates="events") slot = relationship("Slot", back_populates="events")