aaredb/backend/app/models.py

161 lines
5.9 KiB
Python

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")
events = relationship("LogisticsEvent", back_populates="dewar")
return_address = relationship("Address")
contact_person = relationship("ContactPerson")
pucks = relationship("Puck", back_populates="dewar")
dewar_type = relationship("DewarType")
dewar_serial_number = relationship("DewarSerialNumber")
@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)
last_refill = Column(DateTime, default=datetime.utcnow)
time_until_refill = Column(Integer) # store as total seconds
@property
def calculate_time_until_refill(self):
if self.last_refill and self.time_until_refill:
return self.last_refill + self.time_until_refill - datetime.utcnow()
return None
class LogisticsEvent(Base):
__tablename__ = 'logistics_events'
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
dewar_id = Column(Integer, ForeignKey('dewars.id'), nullable=False)
event_type = Column(String, nullable=False)
timestamp = Column(DateTime, default=datetime.utcnow)
dewar = relationship("Dewar", back_populates="events")