changed models and schemasa

This commit is contained in:
GotthardG 2024-11-11 15:00:20 +01:00
parent 7125cc5b50
commit 52fe68b2bc
10 changed files with 279 additions and 112 deletions

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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);
}
}
};

View File

@ -190,6 +190,7 @@ const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
<UploadDialog
open={uploadDialogOpen}
onClose={closeUploadDialog}
selectedShipment={selectedShipment} // <-- Pass selectedShipment here
/>
</Box>
);

View File

@ -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);

View File

@ -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) {

View File

@ -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>
)}