changed models and schemasa
This commit is contained in:
parent
7125cc5b50
commit
52fe68b2bc
@ -102,38 +102,39 @@ shipments = [
|
||||
]
|
||||
|
||||
pucks = [
|
||||
Puck(id=1, puck_name="PUCK001", puck_type="Unipuck", puck_location_in_dewar=1, positions=[], dewar_id=1),
|
||||
Puck(id=2, puck_name="PUCK002", puck_type="Unipuck", puck_location_in_dewar=2, positions=[], dewar_id=1),
|
||||
Puck(id=3, puck_name="PUCK003", puck_type="Unipuck", puck_location_in_dewar=3, positions=[], dewar_id=1),
|
||||
Puck(id=4, puck_name="PUCK004", puck_type="Unipuck", puck_location_in_dewar=4, positions=[], dewar_id=1),
|
||||
Puck(id=5, puck_name="PUCK005", puck_type="Unipuck", puck_location_in_dewar=5, positions=[], dewar_id=1),
|
||||
Puck(id=6, puck_name="PUCK006", puck_type="Unipuck", puck_location_in_dewar=6, positions=[], dewar_id=1),
|
||||
Puck(id=7, puck_name="PUCK007", puck_type="Unipuck", puck_location_in_dewar=7, positions=[], dewar_id=1),
|
||||
Puck(id=8, puck_name="PK001", puck_type="Unipuck", puck_location_in_dewar=1, positions=[], dewar_id=2),
|
||||
Puck(id=9, puck_name="PK002", puck_type="Unipuck", puck_location_in_dewar=2, positions=[], dewar_id=2),
|
||||
Puck(id=10, puck_name="PK003", puck_type="Unipuck", puck_location_in_dewar=3, positions=[], dewar_id=2),
|
||||
Puck(id=11, puck_name="PK004", puck_type="Unipuck", puck_location_in_dewar=4, positions=[], dewar_id=2),
|
||||
Puck(id=12, puck_name="PK005", puck_type="Unipuck", puck_location_in_dewar=5, positions=[], dewar_id=2),
|
||||
Puck(id=13, puck_name="PK006", puck_type="Unipuck", puck_location_in_dewar=6, positions=[], dewar_id=2),
|
||||
Puck(id=14, puck_name="P001", puck_type="Unipuck", puck_location_in_dewar=1, positions=[], dewar_id=3),
|
||||
Puck(id=15, puck_name="P002", puck_type="Unipuck", puck_location_in_dewar=2, positions=[], dewar_id=3),
|
||||
Puck(id=16, puck_name="P003", puck_type="Unipuck", puck_location_in_dewar=3, positions=[], dewar_id=3),
|
||||
Puck(id=17, puck_name="P004", puck_type="Unipuck", puck_location_in_dewar=4, positions=[], dewar_id=3),
|
||||
Puck(id=18, puck_name="P005", puck_type="Unipuck", puck_location_in_dewar=5, positions=[], dewar_id=3),
|
||||
Puck(id=19, puck_name="P006", puck_type="Unipuck", puck_location_in_dewar=6, positions=[], dewar_id=3),
|
||||
Puck(id=20, puck_name="P007", puck_type="Unipuck", puck_location_in_dewar=7, positions=[], dewar_id=3),
|
||||
Puck(id=21, puck_name="PC002", puck_type="Unipuck", puck_location_in_dewar=2, positions=[], dewar_id=4),
|
||||
Puck(id=22, puck_name="PC003", puck_type="Unipuck", puck_location_in_dewar=3, positions=[], dewar_id=4),
|
||||
Puck(id=23, puck_name="PC004", puck_type="Unipuck", puck_location_in_dewar=4, positions=[], dewar_id=4),
|
||||
Puck(id=24, puck_name="PC005", puck_type="Unipuck", puck_location_in_dewar=5, positions=[], dewar_id=4),
|
||||
Puck(id=25, puck_name="PC006", puck_type="Unipuck", puck_location_in_dewar=6, positions=[], dewar_id=4),
|
||||
Puck(id=26, puck_name="PC007", puck_type="Unipuck", puck_location_in_dewar=7, positions=[], dewar_id=4),
|
||||
Puck(id=27, puck_name="PKK004", puck_type="Unipuck", puck_location_in_dewar=4, positions=[], dewar_id=5),
|
||||
Puck(id=28, puck_name="PKK005", puck_type="Unipuck", puck_location_in_dewar=5, positions=[], dewar_id=5),
|
||||
Puck(id=29, puck_name="PKK006", puck_type="Unipuck", puck_location_in_dewar=6, positions=[], dewar_id=5),
|
||||
Puck(id=30, puck_name="PKK007", puck_type="Unipuck", puck_location_in_dewar=7, positions=[], dewar_id=5)
|
||||
Puck(id=1, puck_name="PUCK001", puck_type="Unipuck", puck_location_in_dewar=1, dewar_id=1),
|
||||
Puck(id=2, puck_name="PUCK002", puck_type="Unipuck", puck_location_in_dewar=2, dewar_id=1),
|
||||
Puck(id=3, puck_name="PUCK003", puck_type="Unipuck", puck_location_in_dewar=3, dewar_id=1),
|
||||
Puck(id=4, puck_name="PUCK004", puck_type="Unipuck", puck_location_in_dewar=4, dewar_id=1),
|
||||
Puck(id=5, puck_name="PUCK005", puck_type="Unipuck", puck_location_in_dewar=5, dewar_id=1),
|
||||
Puck(id=6, puck_name="PUCK006", puck_type="Unipuck", puck_location_in_dewar=6, dewar_id=1),
|
||||
Puck(id=7, puck_name="PUCK007", puck_type="Unipuck", puck_location_in_dewar=7, dewar_id=1),
|
||||
Puck(id=8, puck_name="PK001", puck_type="Unipuck", puck_location_in_dewar=1, dewar_id=2),
|
||||
Puck(id=9, puck_name="PK002", puck_type="Unipuck", puck_location_in_dewar=2, dewar_id=2),
|
||||
Puck(id=10, puck_name="PK003", puck_type="Unipuck", puck_location_in_dewar=3, dewar_id=2),
|
||||
Puck(id=11, puck_name="PK004", puck_type="Unipuck", puck_location_in_dewar=4, dewar_id=2),
|
||||
Puck(id=12, puck_name="PK005", puck_type="Unipuck", puck_location_in_dewar=5, dewar_id=2),
|
||||
Puck(id=13, puck_name="PK006", puck_type="Unipuck", puck_location_in_dewar=6, dewar_id=2),
|
||||
Puck(id=14, puck_name="P001", puck_type="Unipuck", puck_location_in_dewar=1, dewar_id=3),
|
||||
Puck(id=15, puck_name="P002", puck_type="Unipuck", puck_location_in_dewar=2, dewar_id=3),
|
||||
Puck(id=16, puck_name="P003", puck_type="Unipuck", puck_location_in_dewar=3, dewar_id=3),
|
||||
Puck(id=17, puck_name="P004", puck_type="Unipuck", puck_location_in_dewar=4, dewar_id=3),
|
||||
Puck(id=18, puck_name="P005", puck_type="Unipuck", puck_location_in_dewar=5, dewar_id=3),
|
||||
Puck(id=19, puck_name="P006", puck_type="Unipuck", puck_location_in_dewar=6, dewar_id=3),
|
||||
Puck(id=20, puck_name="P007", puck_type="Unipuck", puck_location_in_dewar=7, dewar_id=3),
|
||||
Puck(id=21, puck_name="PC002", puck_type="Unipuck", puck_location_in_dewar=2, dewar_id=4),
|
||||
Puck(id=22, puck_name="PC003", puck_type="Unipuck", puck_location_in_dewar=3, dewar_id=4),
|
||||
Puck(id=23, puck_name="PC004", puck_type="Unipuck", puck_location_in_dewar=4, dewar_id=4),
|
||||
Puck(id=24, puck_name="PC005", puck_type="Unipuck", puck_location_in_dewar=5, dewar_id=4),
|
||||
Puck(id=25, puck_name="PC006", puck_type="Unipuck", puck_location_in_dewar=6, dewar_id=4),
|
||||
Puck(id=26, puck_name="PC007", puck_type="Unipuck", puck_location_in_dewar=7, dewar_id=4),
|
||||
Puck(id=27, puck_name="PKK004", puck_type="Unipuck", puck_location_in_dewar=4, dewar_id=5),
|
||||
Puck(id=28, puck_name="PKK005", puck_type="Unipuck", puck_location_in_dewar=5, dewar_id=5),
|
||||
Puck(id=29, puck_name="PKK006", puck_type="Unipuck", puck_location_in_dewar=6, dewar_id=5),
|
||||
Puck(id=30, puck_name="PKK007", puck_type="Unipuck", puck_location_in_dewar=7, dewar_id=5)
|
||||
]
|
||||
|
||||
|
||||
samples = []
|
||||
sample_id_counter = 1
|
||||
|
||||
@ -143,7 +144,11 @@ for puck in pucks:
|
||||
|
||||
for pos in range(1, 17):
|
||||
if pos in occupied_positions:
|
||||
sample = Sample(id=sample_id_counter, sample_name=f"Sample{sample_id_counter:03}", puck_id=puck.id)
|
||||
puck.positions.append(sample)
|
||||
sample = Sample(
|
||||
id=sample_id_counter,
|
||||
sample_name=f"Sample{sample_id_counter:03}",
|
||||
position=pos,
|
||||
puck_id=puck.id
|
||||
)
|
||||
samples.append(sample)
|
||||
sample_id_counter += 1
|
@ -69,11 +69,13 @@ class Dewar(Base):
|
||||
|
||||
@property
|
||||
def number_of_pucks(self) -> int:
|
||||
return calculate_number_of_pucks(self)
|
||||
return len(self.pucks) if self.pucks else 0
|
||||
|
||||
@property
|
||||
def number_of_samples(self) -> int:
|
||||
return calculate_number_of_samples(self)
|
||||
if not self.pucks:
|
||||
return 0
|
||||
return sum(len(puck.samples) for puck in self.pucks)
|
||||
|
||||
|
||||
class Proposal(Base):
|
||||
@ -88,20 +90,24 @@ class Proposal(Base):
|
||||
class Puck(Base):
|
||||
__tablename__ = 'pucks'
|
||||
|
||||
id = Column(String, primary_key=True)
|
||||
puck_name = Column(String)
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
puck_name = Column(String, index=True)
|
||||
puck_type = Column(String)
|
||||
puck_location_in_dewar = Column(Integer)
|
||||
dewar_id = Column(Integer, ForeignKey('dewars.id')) # Note: changed to String
|
||||
|
||||
positions = relationship("Sample", back_populates="puck")
|
||||
dewar = relationship("Dewar", back_populates="pucks")
|
||||
# Foreign keys and relationships
|
||||
dewar_id = Column(Integer, ForeignKey('dewars.id'))
|
||||
dewar = relationship("Dewar", back_populates="pucks") # Properly define the other side of the relationship
|
||||
samples = relationship("Sample", back_populates="puck")
|
||||
|
||||
|
||||
class Sample(Base):
|
||||
__tablename__ = 'samples'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
sample_name = Column(String)
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
sample_name = Column(String, index=True) # Matches `sample_name` in data creation
|
||||
position = Column(Integer) # Matches `position` in data creation script
|
||||
|
||||
# Foreign keys and relationships
|
||||
puck_id = Column(Integer, ForeignKey('pucks.id'))
|
||||
puck = relationship("Puck", back_populates="positions")
|
||||
puck = relationship("Puck", back_populates="samples")
|
||||
|
@ -1,24 +1,27 @@
|
||||
# app/routers/shipment.py
|
||||
|
||||
from fastapi import APIRouter, HTTPException, status, Query, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List, Optional
|
||||
import uuid
|
||||
import json
|
||||
from datetime import date
|
||||
import logging
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.models import Shipment as ShipmentModel, ContactPerson as ContactPersonModel, Address as AddressModel, Proposal as ProposalModel, Dewar as DewarModel
|
||||
from app.schemas import ShipmentCreate, UpdateShipmentComments, Shipment as ShipmentSchema, DewarUpdate, ContactPerson as ContactPersonSchema
|
||||
from app.schemas import Sample as SampleSchema
|
||||
from app.models import Shipment as ShipmentModel, ContactPerson as ContactPersonModel, Address as AddressModel, \
|
||||
Proposal as ProposalModel, Dewar as DewarModel
|
||||
from app.schemas import ShipmentCreate, UpdateShipmentComments, Shipment as ShipmentSchema, DewarUpdate, \
|
||||
ContactPerson as ContactPersonSchema, Sample as SampleSchema, DewarCreate, PuckCreate, SampleCreate
|
||||
from app.database import get_db
|
||||
from app.crud import get_shipments, get_shipment_by_id
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def default_serializer(obj):
|
||||
if isinstance(obj, date):
|
||||
return obj.isoformat()
|
||||
raise TypeError(f"Type {type(obj)} not serializable")
|
||||
|
||||
|
||||
@router.get("", response_model=List[ShipmentSchema])
|
||||
async def fetch_shipments(id: Optional[int] = Query(None), db: Session = Depends(get_db)):
|
||||
if id:
|
||||
@ -35,6 +38,7 @@ async def fetch_shipments(id: Optional[int] = Query(None), db: Session = Depends
|
||||
logging.info(f"Shipment ID: {shipment.id}, Shipment Name: {shipment.shipment_name}")
|
||||
return shipments
|
||||
|
||||
|
||||
@router.post("", response_model=ShipmentSchema, status_code=status.HTTP_201_CREATED)
|
||||
async def create_shipment(shipment: ShipmentCreate, db: Session = Depends(get_db)):
|
||||
contact_person = db.query(ContactPersonModel).filter(ContactPersonModel.id == shipment.contact_person_id).first()
|
||||
@ -68,6 +72,7 @@ async def create_shipment(shipment: ShipmentCreate, db: Session = Depends(get_db
|
||||
|
||||
return db_shipment
|
||||
|
||||
|
||||
@router.delete("/{shipment_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_shipment(id: int, db: Session = Depends(get_db)):
|
||||
shipment = db.query(ShipmentModel).filter(ShipmentModel.id == id).first()
|
||||
@ -77,6 +82,7 @@ async def delete_shipment(id: int, db: Session = Depends(get_db)):
|
||||
db.commit()
|
||||
return
|
||||
|
||||
|
||||
@router.put("/{shipment_id}", response_model=ShipmentSchema)
|
||||
async def update_shipment(id: int, updated_shipment: ShipmentCreate, db: Session = Depends(get_db)):
|
||||
print("Received payload:", json.dumps(updated_shipment.dict(), indent=2, default=default_serializer))
|
||||
@ -145,6 +151,7 @@ async def add_dewar_to_shipment(id: int, dewar_id: int, db: Session = Depends(ge
|
||||
db.refresh(shipment)
|
||||
return shipment
|
||||
|
||||
|
||||
@router.delete("/{shipment_id}/remove_dewar/{dewar_id}", response_model=ShipmentSchema)
|
||||
async def remove_dewar_from_shipment(shipment_id: int, dewar_id: int, db: Session = Depends(get_db)):
|
||||
shipment = db.query(ShipmentModel).filter(ShipmentModel.id == shipment_id).first()
|
||||
@ -160,11 +167,13 @@ async def remove_dewar_from_shipment(shipment_id: int, dewar_id: int, db: Sessio
|
||||
db.refresh(shipment)
|
||||
return shipment
|
||||
|
||||
|
||||
@router.get("/contact_persons", response_model=List[ContactPersonSchema])
|
||||
async def get_shipment_contact_persons(db: Session = Depends(get_db)):
|
||||
contact_persons = db.query(ContactPersonModel).all()
|
||||
return contact_persons
|
||||
|
||||
|
||||
@router.get("/{shipment_id}/samples", response_model=List[SampleSchema])
|
||||
def get_samples_in_shipment(id: int, db: Session = Depends(get_db)):
|
||||
shipment = db.query(ShipmentModel).filter(ShipmentModel.id == id).first()
|
||||
@ -174,27 +183,25 @@ def get_samples_in_shipment(id: int, db: Session = Depends(get_db)):
|
||||
samples = []
|
||||
for dewar in shipment.dewars:
|
||||
for puck in dewar.pucks:
|
||||
samples.extend(puck.positions)
|
||||
samples.extend(puck.samples)
|
||||
|
||||
return samples
|
||||
|
||||
@router.get("/{shipment_id}/dewars/{dewar_id}/samples", response_model=List[SampleSchema])
|
||||
def get_samples_in_dewar(
|
||||
shipment_id: int, dewar_id: int, db: Session = Depends(get_db)
|
||||
):
|
||||
shipment = db.query(ShipmentModel).filter(ShipmentModel.id == shipment_id).first()
|
||||
if shipment is None:
|
||||
|
||||
@router.get("/shipments/{shipment_id}/dewars/{dewar_id}/samples", response_model=List[SampleSchema])
|
||||
def get_samples_in_dewar(shipment_id: int, dewar_id: int, db: Session = Depends(get_db)):
|
||||
shipment = get_shipment_by_id(db, shipment_id)
|
||||
if not shipment:
|
||||
raise HTTPException(status_code=404, detail="Shipment not found")
|
||||
|
||||
dewar = db.query(DewarModel).filter(
|
||||
DewarModel.id == dewar_id, DewarModel.shipment_id == shipment_id
|
||||
).first()
|
||||
if dewar is None:
|
||||
raise HTTPException(status_code=404, detail="Dewar not found in shipment")
|
||||
dewar = next((d for d in shipment.dewars if d.id == dewar_id), None)
|
||||
if not dewar:
|
||||
raise HTTPException(status_code=404, detail="Dewar not found")
|
||||
|
||||
samples = []
|
||||
for puck in dewar.pucks:
|
||||
samples.extend(puck.positions)
|
||||
for sample in puck.samples:
|
||||
samples.append(sample)
|
||||
|
||||
return samples
|
||||
|
||||
@ -209,3 +216,50 @@ async def update_shipment_comments(id: int, comments_data: UpdateShipmentComment
|
||||
db.commit()
|
||||
db.refresh(shipment)
|
||||
return shipment
|
||||
|
||||
|
||||
@router.post("/{shipment_id}/add_dewar_puck_sample", response_model=ShipmentSchema, status_code=status.HTTP_201_CREATED)
|
||||
async def add_dewar_puck_sample_to_shipment(shipment_id: int, payload: DewarCreate, db: Session = Depends(get_db)):
|
||||
shipment = db.query(ShipmentModel).filter(ShipmentModel.id == shipment_id).first()
|
||||
if not shipment:
|
||||
raise HTTPException(status_code=404, detail="Shipment not found")
|
||||
|
||||
for dewar_data in payload.dewars:
|
||||
dewar = Dewar(
|
||||
shipment_id=shipment_id,
|
||||
dewar_name=dewar_data.dewar_name,
|
||||
tracking_number=dewar_data.tracking_number,
|
||||
status=dewar_data.status,
|
||||
contact_person_id=dewar_data.contact_person_id,
|
||||
return_address_id=dewar_data.return_address_id,
|
||||
)
|
||||
db.add(dewar)
|
||||
db.commit()
|
||||
db.refresh(dewar)
|
||||
|
||||
for puck_data in dewar_data.pucks:
|
||||
puck = Puck(
|
||||
dewar_id=dewar.id,
|
||||
puck_name=puck_data.puck_name,
|
||||
puck_type=puck_data.puck_type,
|
||||
puck_location_in_dewar=puck_data.puck_location_in_dewar,
|
||||
)
|
||||
db.add(puck)
|
||||
db.commit()
|
||||
db.refresh(puck)
|
||||
|
||||
for sample_data in puck_data.samples:
|
||||
sample = Sample(
|
||||
puck_id=puck.id,
|
||||
sample_name=sample_data.sample_name,
|
||||
position=sample_data.position,
|
||||
data_collection_parameters=DataCollectionParameters(
|
||||
**sample_data.data_collection_parameters
|
||||
),
|
||||
)
|
||||
db.add(sample)
|
||||
db.commit()
|
||||
db.refresh(sample)
|
||||
|
||||
db.refresh(shipment)
|
||||
return shipment
|
||||
|
@ -1,5 +1,5 @@
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel, EmailStr, constr
|
||||
from pydantic import BaseModel, EmailStr, constr, Field
|
||||
from datetime import date
|
||||
|
||||
|
||||
@ -35,9 +35,11 @@ class DataCollectionParameters(BaseModel):
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class Results(BaseModel):
|
||||
# Define attributes for Results here
|
||||
pass # Placeholder for now, should be expanded later with actual fields
|
||||
pass
|
||||
|
||||
|
||||
# Contact Person schemas
|
||||
class ContactPersonBase(BaseModel):
|
||||
@ -57,12 +59,14 @@ class ContactPerson(ContactPersonBase):
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ContactPersonUpdate(BaseModel):
|
||||
firstname: str | None = None
|
||||
lastname: str | None = None
|
||||
phone_number: str | None = None
|
||||
email: EmailStr | None = None
|
||||
|
||||
|
||||
# Address schemas
|
||||
class AddressCreate(BaseModel):
|
||||
street: str
|
||||
@ -77,21 +81,31 @@ class Address(AddressCreate):
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class AddressUpdate(BaseModel):
|
||||
street: str | None = None
|
||||
city: str | None = None
|
||||
zipcode: str | None = None
|
||||
country: str | None = None
|
||||
|
||||
# Sample schemas
|
||||
|
||||
class Sample(BaseModel):
|
||||
id: int
|
||||
sample_name: str
|
||||
data_collection_parameters: Optional[DataCollectionParameters] = None
|
||||
results: Optional[Results] = None
|
||||
position: int # Position within the puck
|
||||
puck_id: int
|
||||
crystalname: Optional[str] = Field(None)
|
||||
positioninpuck: Optional[int] = Field(None)
|
||||
|
||||
|
||||
class SampleCreate(BaseModel):
|
||||
sample_name: str = Field(..., alias="crystalname")
|
||||
position: int = Field(..., alias="positioninpuck")
|
||||
data_collection_parameters: DataCollectionParameters
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
|
||||
# Puck schemas
|
||||
@ -102,7 +116,7 @@ class PuckBase(BaseModel):
|
||||
|
||||
|
||||
class PuckCreate(PuckBase):
|
||||
positions: List[int] = []
|
||||
pass
|
||||
|
||||
|
||||
class PuckUpdate(BaseModel):
|
||||
@ -110,12 +124,15 @@ class PuckUpdate(BaseModel):
|
||||
puck_type: Optional[str] = None
|
||||
puck_location_in_dewar: Optional[int] = None
|
||||
dewar_id: Optional[int] = None
|
||||
positions: Optional[List[int]] = None
|
||||
|
||||
|
||||
class Puck(PuckBase):
|
||||
class Puck(BaseModel):
|
||||
id: int
|
||||
positions: List[Sample] = []
|
||||
puck_name: str
|
||||
puck_type: str
|
||||
puck_location_in_dewar: int
|
||||
dewar_id: int
|
||||
samples: List[Sample] = [] # List of samples within this puck
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@ -137,8 +154,13 @@ class DewarBase(BaseModel):
|
||||
return_address_id: Optional[int]
|
||||
|
||||
|
||||
class DewarCreate(DewarBase):
|
||||
pass
|
||||
class DewarCreate(BaseModel):
|
||||
dewar_name: str = Field(..., alias="dewarname")
|
||||
tracking_number: Optional[str]
|
||||
status: Optional[str] = None
|
||||
contact_person_id: Optional[int] = None
|
||||
return_address_id: Optional[int] = None
|
||||
pucks: List[PuckCreate] = []
|
||||
|
||||
|
||||
class Dewar(DewarBase):
|
||||
@ -146,7 +168,7 @@ class Dewar(DewarBase):
|
||||
shipment_id: Optional[int]
|
||||
contact_person: Optional[ContactPerson]
|
||||
return_address: Optional[Address]
|
||||
pucks: Optional[List[Puck]] = []
|
||||
pucks: List[Puck] = [] # List of pucks within this dewar
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@ -184,7 +206,7 @@ class Shipment(BaseModel):
|
||||
contact_person: Optional[ContactPerson]
|
||||
return_address: Optional[Address]
|
||||
proposal: Optional[Proposal]
|
||||
dewars: Optional[List[Dewar]] = []
|
||||
dewars: List[Dewar] = []
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@ -198,7 +220,7 @@ class ShipmentCreate(BaseModel):
|
||||
contact_person_id: int
|
||||
return_address_id: int
|
||||
proposal_id: int
|
||||
dewars: Optional[List[DewarUpdate]] = []
|
||||
dewars: List[DewarCreate] = []
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
@ -1,31 +1,27 @@
|
||||
# app/services/shipment_processor.py
|
||||
# Adjusting the ShipmentProcessor for better error handling and alignment
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from app.models import Shipment, Dewar, Puck, Sample
|
||||
from app.models import Shipment, Dewar, Puck, Sample, DataCollectionParameters
|
||||
from app.schemas import ShipmentCreate, ShipmentResponse
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ShipmentProcessor:
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
|
||||
def process_shipment(self, shipment: ShipmentCreate) -> ShipmentResponse:
|
||||
logger = logging.getLogger(__name__)
|
||||
try:
|
||||
# Creating new Shipment
|
||||
new_shipment = Shipment(
|
||||
shipment_name=shipment.shipment_name,
|
||||
shipment_date=shipment.shipment_date,
|
||||
shipment_status=shipment.shipment_status, # Adjusted to match model
|
||||
# other shipment-related fields if any
|
||||
shipment_status=shipment.shipment_status,
|
||||
)
|
||||
self.db.add(new_shipment)
|
||||
self.db.commit()
|
||||
self.db.refresh(new_shipment)
|
||||
|
||||
# Link Dewars
|
||||
for dewar_data in shipment.dewars:
|
||||
dewar = Dewar(
|
||||
shipment_id=new_shipment.id,
|
||||
@ -39,7 +35,6 @@ class ShipmentProcessor:
|
||||
self.db.commit()
|
||||
self.db.refresh(dewar)
|
||||
|
||||
# Link Pucks
|
||||
for puck_data in dewar_data.pucks:
|
||||
puck = Puck(
|
||||
dewar_id=dewar.id,
|
||||
@ -51,18 +46,19 @@ class ShipmentProcessor:
|
||||
self.db.commit()
|
||||
self.db.refresh(puck)
|
||||
|
||||
# Link Samples
|
||||
for sample_data in puck_data.samples:
|
||||
data_collection_params = DataCollectionParameters(
|
||||
**sample_data.data_collection_parameters.dict(by_alias=True))
|
||||
sample = Sample(
|
||||
puck_id=puck.id,
|
||||
sample_name=sample_data.sample_name,
|
||||
position=sample_data.position,
|
||||
data_collection_parameters=data_collection_params
|
||||
)
|
||||
self.db.add(sample)
|
||||
self.db.commit()
|
||||
self.db.refresh(sample)
|
||||
|
||||
# Return a response wrapped in the ShipmentResponse schema
|
||||
return ShipmentResponse(
|
||||
shipment_id=new_shipment.id,
|
||||
status="success",
|
||||
|
@ -42,6 +42,8 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
||||
const [changesMade, setChangesMade] = useState(false);
|
||||
const [feedbackMessage, setFeedbackMessage] = useState('');
|
||||
const [openSnackbar, setOpenSnackbar] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const setInitialContactPerson = () => {
|
||||
@ -92,22 +94,33 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSamples = async () => {
|
||||
if (dewar.id && Array.isArray(dewar.pucks)) {
|
||||
if (dewar.id) {
|
||||
try {
|
||||
const samples = await ShipmentsService.getSamplesInDewarShipmentsShipmentIdDewarsDewarIdSamplesGet(shipmentId, dewar.id);
|
||||
const fetchedSamples = await ShipmentsService.getSamplesInDewarShipmentsShipmentsShipmentIdDewarsDewarIdSamplesGet(shipmentId, dewar.id);
|
||||
console.log("Fetched Samples: ", fetchedSamples);
|
||||
|
||||
const updatedPuckStatuses = dewar.pucks.map(puck => {
|
||||
if (!Array.isArray(puck.positions)) return [];
|
||||
return puck.positions.map(position => {
|
||||
const isOccupied = samples.some(sample => sample.id === position.id);
|
||||
return isOccupied ? 'filled' : 'empty';
|
||||
// Filter samples for the current puck
|
||||
const puckSamples = fetchedSamples.filter(sample => sample.puck_id === puck.id);
|
||||
|
||||
// Initialize positions as 'empty'
|
||||
const statusArray = Array(16).fill('empty');
|
||||
|
||||
// Update positions based on puckSamples' positions
|
||||
puckSamples.forEach(sample => {
|
||||
if (sample.position >= 1 && sample.position <= 16) {
|
||||
statusArray[sample.position - 1] = 'filled'; // Adjust for 0-based index
|
||||
}
|
||||
});
|
||||
|
||||
return statusArray;
|
||||
});
|
||||
|
||||
setPuckStatuses(updatedPuckStatuses);
|
||||
} catch (error) {
|
||||
setFeedbackMessage('Failed to load samples. Please try again later.');
|
||||
setOpenSnackbar(true);
|
||||
setError('Failed to load samples. Please try again later.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -190,6 +190,7 @@ const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
||||
<UploadDialog
|
||||
open={uploadDialogOpen}
|
||||
onClose={closeUploadDialog}
|
||||
selectedShipment={selectedShipment} // <-- Pass selectedShipment here
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
|
@ -13,11 +13,19 @@ import {
|
||||
Button,
|
||||
Box
|
||||
} from '@mui/material';
|
||||
import { SpreadsheetService } from '../../openapi';
|
||||
import { SpreadsheetService, ShipmentsService } from '../../openapi';
|
||||
import * as ExcelJS from 'exceljs';
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
const SpreadsheetTable = ({ raw_data, errors, headers, setRawData, onCancel, fileBlob }) => {
|
||||
const SpreadsheetTable = ({
|
||||
raw_data,
|
||||
errors,
|
||||
headers,
|
||||
setRawData,
|
||||
onCancel,
|
||||
fileBlob,
|
||||
shipmentId // Accept the shipmentId
|
||||
}) => {
|
||||
const [localErrors, setLocalErrors] = useState(errors || []);
|
||||
const [editingCell, setEditingCell] = useState({});
|
||||
const [nonEditableCells, setNonEditableCells] = useState(new Set());
|
||||
@ -25,7 +33,7 @@ const SpreadsheetTable = ({ raw_data, errors, headers, setRawData, onCancel, fil
|
||||
const generateErrorMap = (errorsList) => {
|
||||
const errorMap = new Map();
|
||||
if (Array.isArray(errorsList)) {
|
||||
errorsList.forEach(error => {
|
||||
errorsList.forEach((error) => {
|
||||
const key = `${error.row}-${headers[error.cell]}`;
|
||||
errorMap.set(key, error.message);
|
||||
});
|
||||
@ -64,7 +72,7 @@ const SpreadsheetTable = ({ raw_data, errors, headers, setRawData, onCancel, fil
|
||||
|
||||
currentRow.data[colIndex] = newValue;
|
||||
|
||||
setEditingCell(prev => {
|
||||
setEditingCell((prev) => {
|
||||
const updated = { ...prev };
|
||||
delete updated[`${rowIndex}-${colIndex}`];
|
||||
return updated;
|
||||
@ -80,10 +88,10 @@ const SpreadsheetTable = ({ raw_data, errors, headers, setRawData, onCancel, fil
|
||||
if (response.is_valid !== undefined) {
|
||||
if (response.is_valid) {
|
||||
const updatedErrors = localErrors.filter(
|
||||
error => !(error.row === currentRow.row_num && error.cell === colIndex)
|
||||
(error) => !(error.row === currentRow.row_num && error.cell === colIndex)
|
||||
);
|
||||
setLocalErrors(updatedErrors);
|
||||
setNonEditableCells(prev => new Set([...prev, `${rowIndex}-${colIndex}`]));
|
||||
setNonEditableCells((prev) => new Set([...prev, `${rowIndex}-${colIndex}`]));
|
||||
} else {
|
||||
const updatedErrors = [
|
||||
...localErrors,
|
||||
@ -107,11 +115,75 @@ const SpreadsheetTable = ({ raw_data, errors, headers, setRawData, onCancel, fil
|
||||
const handleSubmit = async () => {
|
||||
if (allCellsValid()) {
|
||||
console.log('All data is valid. Proceeding with submission...');
|
||||
const processedData = createPayload(raw_data);
|
||||
|
||||
try {
|
||||
const response = await ShipmentsService.addDewarPuckSampleToShipmentShipmentsShipmentIdAddDewarPuckSamplePost(shipmentId, processedData);
|
||||
console.log('Shipment processed successfully:', response);
|
||||
|
||||
// Handle success actions, e.g., display notification, reset state, etc.
|
||||
} catch (error) {
|
||||
console.error('Error processing shipment:', error);
|
||||
// Handle error actions, e.g., display notification, etc.
|
||||
}
|
||||
} else {
|
||||
console.log('There are validation errors in the dataset. Please correct them before submission.');
|
||||
}
|
||||
};
|
||||
|
||||
const createPayload = (data) => {
|
||||
const allowedFields = [
|
||||
'priority', 'comments', 'directory', 'proteinname', 'oscillation', 'aperture',
|
||||
'exposure', 'totalrange', 'transmission', 'dose', 'targetresolution', 'datacollectiontype',
|
||||
'processingpipeline', 'spacegroupnumber', 'cellparameters', 'rescutkey', 'rescutvalue',
|
||||
'userresolution', 'pdbid', 'autoprocfull', 'procfull', 'adpenabled', 'noano',
|
||||
'ffcscampaign', 'trustedhigh', 'autoprocextraparams', 'chiphiangles'
|
||||
];
|
||||
|
||||
let dewars = {};
|
||||
|
||||
data.forEach((row) => {
|
||||
const dewarname = row.data[headers.indexOf('dewarname')];
|
||||
const puckname = row.data[headers.indexOf('puckname')];
|
||||
const crystalname = row.data[headers.indexOf('crystalname')];
|
||||
const positioninpuck = row.data[headers.indexOf('positioninpuck')];
|
||||
|
||||
if (!dewars[dewarname]) {
|
||||
dewars[dewarname] = {
|
||||
dewarname: dewarname,
|
||||
pucks: {}
|
||||
};
|
||||
}
|
||||
|
||||
if (!dewars[dewarname].pucks[puckname]) {
|
||||
dewars[dewarname].pucks[puckname] = {
|
||||
puckname: puckname,
|
||||
samples: []
|
||||
};
|
||||
}
|
||||
|
||||
const dataCollectionParams = {};
|
||||
headers.forEach((header, index) => {
|
||||
if (allowedFields.includes(header)) {
|
||||
dataCollectionParams[header] = row.data[index];
|
||||
}
|
||||
});
|
||||
|
||||
dewars[dewarname].pucks[puckname].samples.push({
|
||||
crystalname: crystalname,
|
||||
positioninpuck: positioninpuck,
|
||||
data_collection_parameters: dataCollectionParams
|
||||
});
|
||||
});
|
||||
|
||||
const dewarsList = Object.values(dewars).map(dewar => ({
|
||||
dewarname: dewar.dewarname,
|
||||
pucks: Object.values(dewar.pucks)
|
||||
}));
|
||||
|
||||
return { dewars: dewarsList };
|
||||
};
|
||||
|
||||
const downloadCorrectedSpreadsheet = async () => {
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
await workbook.xlsx.load(fileBlob);
|
||||
|
@ -8,11 +8,8 @@ interface UnipuckProps {
|
||||
|
||||
const Unipuck: React.FC<UnipuckProps> = ({ pucks, samples }) => {
|
||||
const renderPuck = (sampleStatus: string[]) => {
|
||||
if (!sampleStatus) {
|
||||
sampleStatus = Array(16).fill('empty');
|
||||
}
|
||||
|
||||
const puckSVG = (
|
||||
sampleStatus = sampleStatus || Array(16).fill('empty'); // Ensure no null status array
|
||||
return (
|
||||
<svg width="100" height="100" viewBox="0 0 100 100">
|
||||
<circle cx="50" cy="50" r="45" stroke="black" strokeWidth="2" fill="none" />
|
||||
{[...Array(11)].map((_, index) => {
|
||||
@ -29,7 +26,6 @@ const Unipuck: React.FC<UnipuckProps> = ({ pucks, samples }) => {
|
||||
})}
|
||||
</svg>
|
||||
);
|
||||
return puckSVG;
|
||||
};
|
||||
|
||||
if (pucks === 0) {
|
||||
|
@ -23,9 +23,10 @@ import * as ExcelJS from 'exceljs';
|
||||
interface UploadDialogProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
selectedShipment: any; // Adjust the type based on your implementation
|
||||
}
|
||||
|
||||
const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose }) => {
|
||||
const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose, selectedShipment }) => {
|
||||
const [uploadError, setUploadError] = useState<string | null>(null);
|
||||
const [fileSummary, setFileSummary] = useState<{
|
||||
data: any[];
|
||||
@ -37,7 +38,7 @@ const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose }) => {
|
||||
pucks: string[];
|
||||
samples_count: number;
|
||||
samples: string[];
|
||||
headers: string[]; // Headers must be part of this object
|
||||
headers: string[];
|
||||
} | null>(null);
|
||||
const [fileBlob, setFileBlob] = useState<Blob | null>(null); // New state to store the file blob
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
@ -165,6 +166,7 @@ const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose }) => {
|
||||
setRawData={(newRawData) => setFileSummary((prevSummary) => ({ ...prevSummary, raw_data: newRawData }))}
|
||||
onCancel={handleCancel}
|
||||
fileBlob={fileBlob} // Pass the original file blob
|
||||
shipmentId={selectedShipment?.id} // Pass the selected shipment ID
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
|
Loading…
x
Reference in New Issue
Block a user