Fix formatting with black
This commit is contained in:
@ -5,4 +5,11 @@ from .dewar import router as dewar_router
|
||||
from .shipment import router as shipment_router
|
||||
from .auth import router as auth_router
|
||||
|
||||
__all__ = ["address_router", "contact_router", "proposal_router", "dewar_router", "shipment_router", "auth_router"]
|
||||
__all__ = [
|
||||
"address_router",
|
||||
"contact_router",
|
||||
"proposal_router",
|
||||
"dewar_router",
|
||||
"shipment_router",
|
||||
"auth_router",
|
||||
]
|
||||
|
@ -7,23 +7,25 @@ from app.dependencies import get_db
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/", response_model=List[AddressSchema])
|
||||
async def get_return_addresses(db: Session = Depends(get_db)):
|
||||
return db.query(AddressModel).all()
|
||||
|
||||
|
||||
@router.post("/", response_model=AddressSchema, status_code=status.HTTP_201_CREATED)
|
||||
async def create_return_address(address: AddressCreate, db: Session = Depends(get_db)):
|
||||
if db.query(AddressModel).filter(AddressModel.city == address.city).first():
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Address in this city already exists."
|
||||
detail="Address in this city already exists.",
|
||||
)
|
||||
|
||||
db_address = AddressModel(
|
||||
street=address.street,
|
||||
city=address.city,
|
||||
zipcode=address.zipcode,
|
||||
country=address.country
|
||||
country=address.country,
|
||||
)
|
||||
|
||||
db.add(db_address)
|
||||
@ -31,13 +33,15 @@ async def create_return_address(address: AddressCreate, db: Session = Depends(ge
|
||||
db.refresh(db_address)
|
||||
return db_address
|
||||
|
||||
|
||||
@router.put("/{address_id}", response_model=AddressSchema)
|
||||
async def update_return_address(address_id: int, address: AddressUpdate, db: Session = Depends(get_db)):
|
||||
async def update_return_address(
|
||||
address_id: int, address: AddressUpdate, db: Session = Depends(get_db)
|
||||
):
|
||||
db_address = db.query(AddressModel).filter(AddressModel.id == address_id).first()
|
||||
if not db_address:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Address not found."
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail="Address not found."
|
||||
)
|
||||
for key, value in address.dict(exclude_unset=True).items():
|
||||
setattr(db_address, key, value)
|
||||
@ -45,14 +49,14 @@ async def update_return_address(address_id: int, address: AddressUpdate, db: Ses
|
||||
db.refresh(db_address)
|
||||
return db_address
|
||||
|
||||
|
||||
@router.delete("/{address_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_return_address(address_id: int, db: Session = Depends(get_db)):
|
||||
db_address = db.query(AddressModel).filter(AddressModel.id == address_id).first()
|
||||
if not db_address:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Address not found."
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail="Address not found."
|
||||
)
|
||||
db.delete(db_address)
|
||||
db.commit()
|
||||
return
|
||||
return
|
||||
|
@ -26,7 +26,10 @@ SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
|
||||
ALGORITHM = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
||||
|
||||
oauth2_scheme = OAuth2AuthorizationCodeBearer(authorizationUrl="/login", tokenUrl="/token/login")
|
||||
oauth2_scheme = OAuth2AuthorizationCodeBearer(
|
||||
authorizationUrl="/login", tokenUrl="/token/login"
|
||||
)
|
||||
|
||||
|
||||
def create_access_token(data: dict) -> str:
|
||||
to_encode = data.copy()
|
||||
@ -34,6 +37,7 @@ def create_access_token(data: dict) -> str:
|
||||
to_encode.update({"exp": expire})
|
||||
return jwt.encode(to_encode, SECRET_KEY, algorithm="HS256")
|
||||
|
||||
|
||||
async def get_current_user(token: str = Depends(oauth2_scheme)) -> loginData:
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
@ -60,6 +64,7 @@ async def get_current_user(token: str = Depends(oauth2_scheme)) -> loginData:
|
||||
|
||||
return token_data
|
||||
|
||||
|
||||
@router.post("/token/login", response_model=loginToken)
|
||||
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
|
||||
user = mock_users_db.get(form_data.username)
|
||||
|
@ -7,38 +7,48 @@ from app.dependencies import get_db
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# Existing routes
|
||||
@router.get("/", response_model=List[ContactPerson])
|
||||
async def get_contacts(db: Session = Depends(get_db)):
|
||||
return db.query(ContactPersonModel).all()
|
||||
|
||||
|
||||
@router.post("/", response_model=ContactPerson, status_code=status.HTTP_201_CREATED)
|
||||
async def create_contact(contact: ContactPersonCreate, db: Session = Depends(get_db)):
|
||||
if db.query(ContactPersonModel).filter(ContactPersonModel.email == contact.email).first():
|
||||
if (
|
||||
db.query(ContactPersonModel)
|
||||
.filter(ContactPersonModel.email == contact.email)
|
||||
.first()
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="This contact already exists."
|
||||
detail="This contact already exists.",
|
||||
)
|
||||
|
||||
db_contact = ContactPersonModel(
|
||||
firstname=contact.firstname,
|
||||
lastname=contact.lastname,
|
||||
phone_number=contact.phone_number,
|
||||
email=contact.email
|
||||
email=contact.email,
|
||||
)
|
||||
db.add(db_contact)
|
||||
db.commit()
|
||||
db.refresh(db_contact)
|
||||
return db_contact
|
||||
|
||||
|
||||
# New routes
|
||||
@router.put("/{contact_id}", response_model=ContactPerson)
|
||||
async def update_contact(contact_id: int, contact: ContactPersonUpdate, db: Session = Depends(get_db)):
|
||||
db_contact = db.query(ContactPersonModel).filter(ContactPersonModel.id == contact_id).first()
|
||||
async def update_contact(
|
||||
contact_id: int, contact: ContactPersonUpdate, db: Session = Depends(get_db)
|
||||
):
|
||||
db_contact = (
|
||||
db.query(ContactPersonModel).filter(ContactPersonModel.id == contact_id).first()
|
||||
)
|
||||
if not db_contact:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Contact not found."
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail="Contact not found."
|
||||
)
|
||||
for key, value in contact.dict(exclude_unset=True).items():
|
||||
setattr(db_contact, key, value)
|
||||
@ -46,14 +56,16 @@ async def update_contact(contact_id: int, contact: ContactPersonUpdate, db: Sess
|
||||
db.refresh(db_contact)
|
||||
return db_contact
|
||||
|
||||
|
||||
@router.delete("/{contact_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_contact(contact_id: int, db: Session = Depends(get_db)):
|
||||
db_contact = db.query(ContactPersonModel).filter(ContactPersonModel.id == contact_id).first()
|
||||
db_contact = (
|
||||
db.query(ContactPersonModel).filter(ContactPersonModel.id == contact_id).first()
|
||||
)
|
||||
if not db_contact:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Contact not found."
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail="Contact not found."
|
||||
)
|
||||
db.delete(db_contact)
|
||||
db.commit()
|
||||
return
|
||||
return
|
||||
|
@ -13,7 +13,7 @@ from app.schemas import (
|
||||
DewarTypeCreate,
|
||||
DewarSerialNumber as DewarSerialNumberSchema,
|
||||
DewarSerialNumberCreate,
|
||||
Shipment as ShipmentSchema # Clearer name for schema
|
||||
Shipment as ShipmentSchema, # Clearer name for schema
|
||||
)
|
||||
from app.models import (
|
||||
Dewar as DewarModel,
|
||||
@ -21,7 +21,7 @@ from app.models import (
|
||||
Sample as SampleModel,
|
||||
DewarType as DewarTypeModel,
|
||||
DewarSerialNumber as DewarSerialNumberModel,
|
||||
Shipment as ShipmentModel # Clearer name for model
|
||||
Shipment as ShipmentModel, # Clearer name for model
|
||||
)
|
||||
from app.dependencies import get_db
|
||||
import uuid
|
||||
@ -32,23 +32,32 @@ from PIL import ImageFont, ImageDraw, Image
|
||||
from reportlab.lib.pagesizes import A5, landscape
|
||||
from reportlab.lib.units import cm
|
||||
from reportlab.pdfgen import canvas
|
||||
from app.crud import get_shipments, get_shipment_by_id # Import CRUD functions for shipment
|
||||
from app.crud import (
|
||||
get_shipments,
|
||||
get_shipment_by_id,
|
||||
) # Import CRUD functions for shipment
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def generate_unique_id(db: Session, length: int = 16) -> str:
|
||||
while True:
|
||||
base_string = f"{time.time()}{random.randint(0, 10 ** 6)}"
|
||||
hash_object = hashlib.sha256(base_string.encode())
|
||||
hash_digest = hash_object.hexdigest()
|
||||
unique_id = ''.join(random.choices(hash_digest, k=length))
|
||||
existing_dewar = db.query(DewarModel).filter(DewarModel.unique_id == unique_id).first()
|
||||
unique_id = "".join(random.choices(hash_digest, k=length))
|
||||
existing_dewar = (
|
||||
db.query(DewarModel).filter(DewarModel.unique_id == unique_id).first()
|
||||
)
|
||||
if not existing_dewar:
|
||||
break
|
||||
return unique_id
|
||||
|
||||
|
||||
@router.post("/", response_model=DewarSchema, status_code=status.HTTP_201_CREATED)
|
||||
async def create_dewar(dewar: DewarCreate, db: Session = Depends(get_db)) -> DewarSchema:
|
||||
async def create_dewar(
|
||||
dewar: DewarCreate, db: Session = Depends(get_db)
|
||||
) -> DewarSchema:
|
||||
try:
|
||||
db_dewar = DewarModel(
|
||||
dewar_name=dewar.dewar_name,
|
||||
@ -96,6 +105,7 @@ async def create_dewar(dewar: DewarCreate, db: Session = Depends(get_db)) -> Dew
|
||||
logging.error(f"Validation error occurred: {e}")
|
||||
raise HTTPException(status_code=400, detail="Validation error")
|
||||
|
||||
|
||||
@router.post("/{dewar_id}/generate-qrcode")
|
||||
async def generate_dewar_qrcode(dewar_id: int, db: Session = Depends(get_db)):
|
||||
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
|
||||
@ -109,7 +119,7 @@ async def generate_dewar_qrcode(dewar_id: int, db: Session = Depends(get_db)):
|
||||
qr = qrcode.QRCode(version=1, box_size=10, border=5)
|
||||
qr.add_data(dewar.unique_id)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image(fill='black', back_color='white')
|
||||
img = qr.make_image(fill="black", back_color="white")
|
||||
|
||||
buf = io.BytesIO()
|
||||
img.save(buf)
|
||||
@ -120,6 +130,7 @@ async def generate_dewar_qrcode(dewar_id: int, db: Session = Depends(get_db)):
|
||||
|
||||
return {"message": "QR Code generated", "qrcode": dewar.unique_id}
|
||||
|
||||
|
||||
def generate_label(dewar):
|
||||
buffer = BytesIO()
|
||||
# Set page orientation to landscape
|
||||
@ -138,25 +149,36 @@ def generate_label(dewar):
|
||||
|
||||
# Desired logo width in the PDF (you can adjust this size)
|
||||
desired_logo_width = 4 * cm
|
||||
desired_logo_height = desired_logo_width / logo_aspect_ratio # maintain aspect ratio
|
||||
desired_logo_height = (
|
||||
desired_logo_width / logo_aspect_ratio
|
||||
) # maintain aspect ratio
|
||||
|
||||
# Draw header text
|
||||
c.setFont("Helvetica-Bold", 16)
|
||||
c.drawString(2 * cm, page_height - 2 * cm, "Paul Scherrer Institut")
|
||||
|
||||
# Draw the Heidi logo with preserved aspect ratio
|
||||
c.drawImage(png_logo_path, page_width - desired_logo_width - 2 * cm,
|
||||
page_height - desired_logo_height - 2 * cm,
|
||||
width=desired_logo_width, height=desired_logo_height, mask='auto')
|
||||
c.drawImage(
|
||||
png_logo_path,
|
||||
page_width - desired_logo_width - 2 * cm,
|
||||
page_height - desired_logo_height - 2 * cm,
|
||||
width=desired_logo_width,
|
||||
height=desired_logo_height,
|
||||
mask="auto",
|
||||
)
|
||||
|
||||
# Draw details section
|
||||
c.setFont("Helvetica", 12)
|
||||
|
||||
y_position = page_height - 4 * cm # Adjusted to ensure text doesn't overlap with the logo
|
||||
y_position = (
|
||||
page_height - 4 * cm
|
||||
) # Adjusted to ensure text doesn't overlap with the logo
|
||||
line_height = 0.8 * cm
|
||||
|
||||
if dewar.shipment:
|
||||
c.drawString(2 * cm, y_position, f"Shipment Name: {dewar.shipment.shipment_name}")
|
||||
c.drawString(
|
||||
2 * cm, y_position, f"Shipment Name: {dewar.shipment.shipment_name}"
|
||||
)
|
||||
y_position -= line_height
|
||||
|
||||
c.drawString(2 * cm, y_position, f"Dewar Name: {dewar.dewar_name}")
|
||||
@ -167,7 +189,11 @@ def generate_label(dewar):
|
||||
|
||||
if dewar.contact_person:
|
||||
contact_person = dewar.contact_person
|
||||
c.drawString(2 * cm, y_position, f"Contact: {contact_person.firstname} {contact_person.lastname}")
|
||||
c.drawString(
|
||||
2 * cm,
|
||||
y_position,
|
||||
f"Contact: {contact_person.firstname} {contact_person.lastname}",
|
||||
)
|
||||
y_position -= line_height
|
||||
c.drawString(2 * cm, y_position, f"Email: {contact_person.email}")
|
||||
y_position -= line_height
|
||||
@ -191,15 +217,17 @@ def generate_label(dewar):
|
||||
qr = qrcode.QRCode(version=1, box_size=10, border=4)
|
||||
qr.add_data(dewar.unique_id)
|
||||
qr.make(fit=True)
|
||||
qr_img = qr.make_image(fill='black', back_color='white').convert("RGBA")
|
||||
qr_img = qr.make_image(fill="black", back_color="white").convert("RGBA")
|
||||
|
||||
# Save this QR code to a temporary file
|
||||
with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_file:
|
||||
qr_img.save(temp_file, format='PNG')
|
||||
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as temp_file:
|
||||
qr_img.save(temp_file, format="PNG")
|
||||
temp_file_path = temp_file.name
|
||||
|
||||
# Add QR code to PDF
|
||||
c.drawImage(temp_file_path, page_width - 6 * cm, 5 * cm, width=4 * cm, height=4 * cm)
|
||||
c.drawImage(
|
||||
temp_file_path, page_width - 6 * cm, 5 * cm, width=4 * cm, height=4 * cm
|
||||
)
|
||||
|
||||
# Add footer text
|
||||
c.setFont("Helvetica", 10)
|
||||
@ -207,7 +235,9 @@ def generate_label(dewar):
|
||||
|
||||
# Draw border
|
||||
c.setLineWidth(1)
|
||||
c.rect(1 * cm, 1 * cm, page_width - 2 * cm, page_height - 2 * cm) # Adjusted dimensions
|
||||
c.rect(
|
||||
1 * cm, 1 * cm, page_width - 2 * cm, page_height - 2 * cm
|
||||
) # Adjusted dimensions
|
||||
|
||||
# Finalize the canvas
|
||||
c.showPage()
|
||||
@ -220,25 +250,38 @@ def generate_label(dewar):
|
||||
|
||||
return buffer
|
||||
|
||||
|
||||
@router.get("/{dewar_id}/download-label", response_class=Response)
|
||||
async def download_dewar_label(dewar_id: int, db: Session = Depends(get_db)):
|
||||
dewar = db.query(DewarModel).options(
|
||||
joinedload(DewarModel.pucks).joinedload(PuckModel.samples),
|
||||
joinedload(DewarModel.contact_person),
|
||||
joinedload(DewarModel.return_address),
|
||||
joinedload(DewarModel.shipment)
|
||||
).filter(DewarModel.id == dewar_id).first()
|
||||
dewar = (
|
||||
db.query(DewarModel)
|
||||
.options(
|
||||
joinedload(DewarModel.pucks).joinedload(PuckModel.samples),
|
||||
joinedload(DewarModel.contact_person),
|
||||
joinedload(DewarModel.return_address),
|
||||
joinedload(DewarModel.shipment),
|
||||
)
|
||||
.filter(DewarModel.id == dewar_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
if not dewar:
|
||||
raise HTTPException(status_code=404, detail="Dewar not found")
|
||||
if not dewar.unique_id:
|
||||
raise HTTPException(status_code=404, detail="QR Code not generated for this dewar")
|
||||
raise HTTPException(
|
||||
status_code=404, detail="QR Code not generated for this dewar"
|
||||
)
|
||||
|
||||
buffer = generate_label(dewar)
|
||||
|
||||
return Response(buffer.getvalue(), media_type="application/pdf", headers={
|
||||
"Content-Disposition": f"attachment; filename=dewar_label_{dewar.id}.pdf"
|
||||
})
|
||||
return Response(
|
||||
buffer.getvalue(),
|
||||
media_type="application/pdf",
|
||||
headers={
|
||||
"Content-Disposition": f"attachment; filename=dewar_label_{dewar.id}.pdf"
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@router.get("/", response_model=List[DewarSchema])
|
||||
async def get_dewars(db: Session = Depends(get_db)):
|
||||
@ -249,13 +292,23 @@ async def get_dewars(db: Session = Depends(get_db)):
|
||||
logging.error(f"Database error occurred: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/dewar-types", response_model=List[DewarTypeSchema])
|
||||
def get_dewar_types(db: Session = Depends(get_db)):
|
||||
return db.query(DewarTypeModel).all()
|
||||
|
||||
@router.get("/dewar-types/{type_id}/serial-numbers", response_model=List[DewarSerialNumberSchema])
|
||||
|
||||
@router.get(
|
||||
"/dewar-types/{type_id}/serial-numbers",
|
||||
response_model=List[DewarSerialNumberSchema],
|
||||
)
|
||||
def get_serial_numbers(type_id: int, db: Session = Depends(get_db)):
|
||||
return db.query(DewarSerialNumberModel).filter(DewarSerialNumberModel.dewar_type_id == type_id).all()
|
||||
return (
|
||||
db.query(DewarSerialNumberModel)
|
||||
.filter(DewarSerialNumberModel.dewar_type_id == type_id)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
@router.post("/dewar-types", response_model=DewarTypeSchema)
|
||||
def create_dewar_type(dewar_type: DewarTypeCreate, db: Session = Depends(get_db)):
|
||||
@ -265,14 +318,18 @@ def create_dewar_type(dewar_type: DewarTypeCreate, db: Session = Depends(get_db)
|
||||
db.refresh(db_type)
|
||||
return db_type
|
||||
|
||||
|
||||
@router.post("/dewar-serial-numbers", response_model=DewarSerialNumberSchema)
|
||||
def create_dewar_serial_number(serial_number: DewarSerialNumberCreate, db: Session = Depends(get_db)):
|
||||
def create_dewar_serial_number(
|
||||
serial_number: DewarSerialNumberCreate, db: Session = Depends(get_db)
|
||||
):
|
||||
db_serial = DewarSerialNumberModel(**serial_number.dict())
|
||||
db.add(db_serial)
|
||||
db.commit()
|
||||
db.refresh(db_serial)
|
||||
return db_serial
|
||||
|
||||
|
||||
@router.get("/dewar-serial-numbers", response_model=List[DewarSerialNumberSchema])
|
||||
def get_all_serial_numbers(db: Session = Depends(get_db)):
|
||||
try:
|
||||
@ -282,22 +339,31 @@ def get_all_serial_numbers(db: Session = Depends(get_db)):
|
||||
logging.error(f"Database error occurred: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/{dewar_id}", response_model=DewarSchema)
|
||||
async def get_dewar(dewar_id: int, db: Session = Depends(get_db)):
|
||||
dewar = db.query(DewarModel).options(
|
||||
joinedload(DewarModel.pucks).joinedload(PuckModel.samples),
|
||||
joinedload(DewarModel.contact_person),
|
||||
joinedload(DewarModel.return_address),
|
||||
joinedload(DewarModel.shipment)
|
||||
).filter(DewarModel.id == dewar_id).first()
|
||||
dewar = (
|
||||
db.query(DewarModel)
|
||||
.options(
|
||||
joinedload(DewarModel.pucks).joinedload(PuckModel.samples),
|
||||
joinedload(DewarModel.contact_person),
|
||||
joinedload(DewarModel.return_address),
|
||||
joinedload(DewarModel.shipment),
|
||||
)
|
||||
.filter(DewarModel.id == dewar_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
if not dewar:
|
||||
raise HTTPException(status_code=404, detail="Dewar not found")
|
||||
|
||||
return DewarSchema.from_orm(dewar)
|
||||
|
||||
|
||||
@router.put("/{dewar_id}", response_model=DewarSchema)
|
||||
async def update_dewar(dewar_id: int, dewar_update: DewarUpdate, db: Session = Depends(get_db)) -> DewarSchema:
|
||||
async def update_dewar(
|
||||
dewar_id: int, dewar_update: DewarUpdate, db: Session = Depends(get_db)
|
||||
) -> DewarSchema:
|
||||
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
|
||||
|
||||
if not dewar:
|
||||
@ -311,6 +377,7 @@ async def update_dewar(dewar_id: int, dewar_update: DewarUpdate, db: Session = D
|
||||
db.refresh(dewar)
|
||||
return dewar
|
||||
|
||||
|
||||
@router.delete("/{dewar_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_dewar(dewar_id: int, db: Session = Depends(get_db)):
|
||||
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
|
||||
@ -322,6 +389,7 @@ async def delete_dewar(dewar_id: int, db: Session = Depends(get_db)):
|
||||
db.commit()
|
||||
return
|
||||
|
||||
|
||||
# New routes for shipments
|
||||
@router.get("/shipments", response_model=List[ShipmentSchema])
|
||||
async def get_all_shipments(db: Session = Depends(get_db)):
|
||||
@ -332,6 +400,7 @@ async def get_all_shipments(db: Session = Depends(get_db)):
|
||||
logging.error(f"Database error occurred: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/shipments/{id}", response_model=ShipmentSchema)
|
||||
async def get_single_shipment(id: int, db: Session = Depends(get_db)):
|
||||
try:
|
||||
@ -341,4 +410,4 @@ async def get_single_shipment(id: int, db: Session = Depends(get_db)):
|
||||
return shipment
|
||||
except SQLAlchemyError as e:
|
||||
logging.error(f"Database error occurred: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
@ -2,7 +2,11 @@ from fastapi import APIRouter, HTTPException, Depends
|
||||
from pydantic import ValidationError
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from typing import List, Optional
|
||||
from ..models import Dewar as DewarModel, Slot as SlotModel, LogisticsEvent as LogisticsEventModel
|
||||
from ..models import (
|
||||
Dewar as DewarModel,
|
||||
Slot as SlotModel,
|
||||
LogisticsEvent as LogisticsEventModel,
|
||||
)
|
||||
from ..schemas import LogisticsEventCreate, SlotSchema, Dewar as DewarSchema
|
||||
from ..database import get_db
|
||||
import logging
|
||||
@ -14,7 +18,9 @@ logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def calculate_time_until_refill(last_refill: Optional[datetime], refill_interval_hours: int = 1) -> int:
|
||||
def calculate_time_until_refill(
|
||||
last_refill: Optional[datetime], refill_interval_hours: int = 1
|
||||
) -> int:
|
||||
refill_interval = timedelta(hours=refill_interval_hours)
|
||||
now = datetime.now()
|
||||
|
||||
@ -27,30 +33,54 @@ def calculate_time_until_refill(last_refill: Optional[datetime], refill_interval
|
||||
|
||||
@router.post("/dewars/return", response_model=DewarSchema)
|
||||
async def return_to_storage(data: LogisticsEventCreate, db: Session = Depends(get_db)):
|
||||
logger.info(f"Returning dewar to storage: {data.dewar_qr_code} at location {data.location_qr_code}")
|
||||
logger.info(
|
||||
f"Returning dewar to storage: {data.dewar_qr_code} at location {data.location_qr_code}"
|
||||
)
|
||||
|
||||
try:
|
||||
# Log the incoming payload
|
||||
logger.info("Received payload: %s", data.json())
|
||||
|
||||
dewar = db.query(DewarModel).filter(DewarModel.unique_id == data.dewar_qr_code).first()
|
||||
dewar = (
|
||||
db.query(DewarModel)
|
||||
.filter(DewarModel.unique_id == data.dewar_qr_code)
|
||||
.first()
|
||||
)
|
||||
if not dewar:
|
||||
logger.error(f"Dewar not found for unique ID: {data.dewar_qr_code}")
|
||||
raise HTTPException(status_code=404, detail="Dewar not found")
|
||||
|
||||
original_slot = db.query(SlotModel).filter(SlotModel.dewar_unique_id == data.dewar_qr_code).first()
|
||||
original_slot = (
|
||||
db.query(SlotModel)
|
||||
.filter(SlotModel.dewar_unique_id == data.dewar_qr_code)
|
||||
.first()
|
||||
)
|
||||
if original_slot and original_slot.qr_code != data.location_qr_code:
|
||||
logger.error(f"Dewar {data.dewar_qr_code} is associated with slot {original_slot.qr_code}")
|
||||
raise HTTPException(status_code=400, detail=f"Dewar {data.dewar_qr_code} is associated with a different slot {original_slot.qr_code}.")
|
||||
logger.error(
|
||||
f"Dewar {data.dewar_qr_code} is associated with slot {original_slot.qr_code}"
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Dewar {data.dewar_qr_code} is associated with a different slot {original_slot.qr_code}.",
|
||||
)
|
||||
|
||||
slot = db.query(SlotModel).filter(SlotModel.qr_code == data.location_qr_code).first()
|
||||
slot = (
|
||||
db.query(SlotModel)
|
||||
.filter(SlotModel.qr_code == data.location_qr_code)
|
||||
.first()
|
||||
)
|
||||
if not slot:
|
||||
logger.error(f"Slot not found for QR code: {data.location_qr_code}")
|
||||
raise HTTPException(status_code=404, detail="Slot not found")
|
||||
|
||||
if slot.occupied and slot.dewar_unique_id != data.dewar_qr_code:
|
||||
logger.error(f"Slot {data.location_qr_code} is already occupied by another dewar")
|
||||
raise HTTPException(status_code=400, detail="Selected slot is already occupied by another dewar")
|
||||
logger.error(
|
||||
f"Slot {data.location_qr_code} is already occupied by another dewar"
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Selected slot is already occupied by another dewar",
|
||||
)
|
||||
|
||||
# Update slot with dewar information
|
||||
slot.dewar_unique_id = dewar.unique_id
|
||||
@ -61,7 +91,9 @@ async def return_to_storage(data: LogisticsEventCreate, db: Session = Depends(ge
|
||||
log_event(db, dewar.id, slot.id, "returned")
|
||||
db.commit()
|
||||
|
||||
logger.info(f"Dewar {data.dewar_qr_code} successfully returned to storage slot {slot.qr_code}.")
|
||||
logger.info(
|
||||
f"Dewar {data.dewar_qr_code} successfully returned to storage slot {slot.qr_code}."
|
||||
)
|
||||
db.refresh(dewar)
|
||||
return dewar
|
||||
except ValidationError as e:
|
||||
@ -71,6 +103,7 @@ async def return_to_storage(data: LogisticsEventCreate, db: Session = Depends(ge
|
||||
logger.error(f"Unexpected error: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.post("/dewar/scan", response_model=dict)
|
||||
async def scan_dewar(event_data: LogisticsEventCreate, db: Session = Depends(get_db)):
|
||||
logger.info(f"Received event data: {event_data}")
|
||||
@ -82,7 +115,9 @@ async def scan_dewar(event_data: LogisticsEventCreate, db: Session = Depends(get
|
||||
# Validate Dewar QR Code
|
||||
if not dewar_qr_code or not dewar_qr_code.strip():
|
||||
logger.error("Dewar QR Code is null or empty")
|
||||
raise HTTPException(status_code=422, detail="Dewar QR Code cannot be null or empty")
|
||||
raise HTTPException(
|
||||
status_code=422, detail="Dewar QR Code cannot be null or empty"
|
||||
)
|
||||
|
||||
# Retrieve the Dewar
|
||||
dewar = db.query(DewarModel).filter(DewarModel.unique_id == dewar_qr_code).first()
|
||||
@ -92,31 +127,42 @@ async def scan_dewar(event_data: LogisticsEventCreate, db: Session = Depends(get
|
||||
|
||||
# Check for Outgoing QR Codes and set transaction type
|
||||
if location_qr_code in ["Outgoing X10-SA", "Outgoing X06-SA"]:
|
||||
transaction_type = 'outgoing'
|
||||
transaction_type = "outgoing"
|
||||
|
||||
# Retrieve the Slot associated with the Dewar (for outgoing)
|
||||
slot = None
|
||||
if transaction_type == 'outgoing':
|
||||
slot = db.query(SlotModel).filter(SlotModel.dewar_unique_id == dewar.unique_id).first()
|
||||
if transaction_type == "outgoing":
|
||||
slot = (
|
||||
db.query(SlotModel)
|
||||
.filter(SlotModel.dewar_unique_id == dewar.unique_id)
|
||||
.first()
|
||||
)
|
||||
if not slot:
|
||||
logger.error(f"No slot associated with dewar for outgoing: {dewar_qr_code}")
|
||||
raise HTTPException(status_code=404, detail="No slot associated with dewar for outgoing")
|
||||
raise HTTPException(
|
||||
status_code=404, detail="No slot associated with dewar for outgoing"
|
||||
)
|
||||
|
||||
# Incoming Logic
|
||||
if transaction_type == 'incoming':
|
||||
if transaction_type == "incoming":
|
||||
slot = db.query(SlotModel).filter(SlotModel.qr_code == location_qr_code).first()
|
||||
if not slot or slot.occupied:
|
||||
logger.error(f"Slot not found or already occupied: {location_qr_code}")
|
||||
raise HTTPException(status_code=400, detail="Slot not found or already occupied")
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Slot not found or already occupied"
|
||||
)
|
||||
slot.dewar_unique_id = dewar.unique_id
|
||||
slot.occupied = True
|
||||
elif transaction_type == 'outgoing':
|
||||
elif transaction_type == "outgoing":
|
||||
if not slot.occupied or slot.dewar_unique_id != dewar.unique_id:
|
||||
logger.error(f"Slot not valid for outgoing: {location_qr_code}")
|
||||
raise HTTPException(status_code=400, detail="Dewar not associated with the slot for outgoing")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Dewar not associated with the slot for outgoing",
|
||||
)
|
||||
slot.dewar_unique_id = None
|
||||
slot.occupied = False
|
||||
elif transaction_type == 'beamline':
|
||||
elif transaction_type == "beamline":
|
||||
slot = db.query(SlotModel).filter(SlotModel.qr_code == location_qr_code).first()
|
||||
if not slot:
|
||||
logger.error(f"Beamline location not found: {location_qr_code}")
|
||||
@ -128,10 +174,12 @@ async def scan_dewar(event_data: LogisticsEventCreate, db: Session = Depends(get
|
||||
log_event(db, dewar.id, slot.id if slot else None, transaction_type)
|
||||
db.commit()
|
||||
logger.info(
|
||||
f"Transaction completed: {transaction_type} for dewar {dewar_qr_code} in slot {slot.qr_code if slot else 'N/A'}")
|
||||
f"Transaction completed: {transaction_type} for dewar {dewar_qr_code} in slot {slot.qr_code if slot else 'N/A'}"
|
||||
)
|
||||
|
||||
return {"message": "Status updated successfully"}
|
||||
|
||||
|
||||
@router.get("/slots", response_model=List[SlotSchema])
|
||||
async def get_all_slots(db: Session = Depends(get_db)):
|
||||
slots = db.query(SlotModel).options(joinedload(SlotModel.dewar)).all()
|
||||
@ -147,14 +195,16 @@ async def get_all_slots(db: Session = Depends(get_db)):
|
||||
|
||||
if slot.dewar_unique_id:
|
||||
# Calculate time until refill
|
||||
last_refill_event = db.query(LogisticsEventModel) \
|
||||
.join(DewarModel, DewarModel.id == LogisticsEventModel.dewar_id) \
|
||||
last_refill_event = (
|
||||
db.query(LogisticsEventModel)
|
||||
.join(DewarModel, DewarModel.id == LogisticsEventModel.dewar_id)
|
||||
.filter(
|
||||
DewarModel.unique_id == slot.dewar.unique_id,
|
||||
LogisticsEventModel.event_type == "refill"
|
||||
) \
|
||||
.order_by(LogisticsEventModel.timestamp.desc()) \
|
||||
DewarModel.unique_id == slot.dewar.unique_id,
|
||||
LogisticsEventModel.event_type == "refill",
|
||||
)
|
||||
.order_by(LogisticsEventModel.timestamp.desc())
|
||||
.first()
|
||||
)
|
||||
|
||||
if last_refill_event:
|
||||
last_refill = last_refill_event.timestamp
|
||||
@ -163,21 +213,27 @@ async def get_all_slots(db: Session = Depends(get_db)):
|
||||
time_until_refill = -1
|
||||
|
||||
# Fetch the latest beamline event
|
||||
last_beamline_event = db.query(LogisticsEventModel) \
|
||||
.join(DewarModel, DewarModel.id == LogisticsEventModel.dewar_id) \
|
||||
last_beamline_event = (
|
||||
db.query(LogisticsEventModel)
|
||||
.join(DewarModel, DewarModel.id == LogisticsEventModel.dewar_id)
|
||||
.filter(
|
||||
DewarModel.unique_id == slot.dewar.unique_id,
|
||||
LogisticsEventModel.event_type == "beamline"
|
||||
) \
|
||||
.order_by(LogisticsEventModel.timestamp.desc()) \
|
||||
DewarModel.unique_id == slot.dewar.unique_id,
|
||||
LogisticsEventModel.event_type == "beamline",
|
||||
)
|
||||
.order_by(LogisticsEventModel.timestamp.desc())
|
||||
.first()
|
||||
)
|
||||
|
||||
if last_beamline_event:
|
||||
# Set retrievedTimestamp to the timestamp of the beamline event
|
||||
retrievedTimestamp = last_beamline_event.timestamp.isoformat()
|
||||
|
||||
# Fetch the associated slot's label for beamlineLocation
|
||||
associated_slot = db.query(SlotModel).filter(SlotModel.id == last_beamline_event.slot_id).first()
|
||||
associated_slot = (
|
||||
db.query(SlotModel)
|
||||
.filter(SlotModel.id == last_beamline_event.slot_id)
|
||||
.first()
|
||||
)
|
||||
beamlineLocation = associated_slot.label if associated_slot else None
|
||||
|
||||
# Mark as being at a beamline
|
||||
@ -204,7 +260,11 @@ async def get_all_slots(db: Session = Depends(get_db)):
|
||||
at_beamline=at_beamline,
|
||||
retrievedTimestamp=retrievedTimestamp,
|
||||
beamlineLocation=beamlineLocation,
|
||||
shipment_name=slot.dewar.shipment.shipment_name if slot.dewar and slot.dewar.shipment else None,
|
||||
shipment_name=(
|
||||
slot.dewar.shipment.shipment_name
|
||||
if slot.dewar and slot.dewar.shipment
|
||||
else None
|
||||
),
|
||||
contact_person=contact_person,
|
||||
local_contact="local contact placeholder",
|
||||
)
|
||||
@ -214,7 +274,6 @@ async def get_all_slots(db: Session = Depends(get_db)):
|
||||
return slots_with_refill_time
|
||||
|
||||
|
||||
|
||||
@router.post("/dewar/refill", response_model=dict)
|
||||
async def refill_dewar(qr_code: str, db: Session = Depends(get_db)):
|
||||
logger.info(f"Refilling dewar with QR code: {qr_code}")
|
||||
@ -236,9 +295,14 @@ async def refill_dewar(qr_code: str, db: Session = Depends(get_db)):
|
||||
db.commit()
|
||||
|
||||
time_until_refill_seconds = calculate_time_until_refill(now)
|
||||
logger.info(f"Dewar refilled successfully with time_until_refill: {time_until_refill_seconds}")
|
||||
logger.info(
|
||||
f"Dewar refilled successfully with time_until_refill: {time_until_refill_seconds}"
|
||||
)
|
||||
|
||||
return {"message": "Dewar refilled successfully", "time_until_refill": time_until_refill_seconds}
|
||||
return {
|
||||
"message": "Dewar refilled successfully",
|
||||
"time_until_refill": time_until_refill_seconds,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/dewars", response_model=List[DewarSchema])
|
||||
@ -250,7 +314,9 @@ async def get_all_dewars(db: Session = Depends(get_db)):
|
||||
@router.get("/dewar/{unique_id}", response_model=DewarSchema)
|
||||
async def get_dewar_by_unique_id(unique_id: str, db: Session = Depends(get_db)):
|
||||
logger.info(f"Received request for dewar with unique_id: {unique_id}")
|
||||
dewar = db.query(DewarModel).filter(DewarModel.unique_id == unique_id.strip()).first()
|
||||
dewar = (
|
||||
db.query(DewarModel).filter(DewarModel.unique_id == unique_id.strip()).first()
|
||||
)
|
||||
if not dewar:
|
||||
logger.warning(f"Dewar with unique_id '{unique_id}' not found.")
|
||||
raise HTTPException(status_code=404, detail="Dewar not found")
|
||||
@ -263,8 +329,10 @@ def log_event(db: Session, dewar_id: int, slot_id: Optional[int], event_type: st
|
||||
dewar_id=dewar_id,
|
||||
slot_id=slot_id,
|
||||
event_type=event_type,
|
||||
timestamp=datetime.now()
|
||||
timestamp=datetime.now(),
|
||||
)
|
||||
db.add(new_event)
|
||||
db.commit()
|
||||
logger.info(f"Logged event: {event_type} for dewar: {dewar_id} in slot: {slot_id if slot_id else 'N/A'}")
|
||||
logger.info(
|
||||
f"Logged event: {event_type} for dewar: {dewar_id} in slot: {slot_id if slot_id else 'N/A'}"
|
||||
)
|
||||
|
@ -8,6 +8,7 @@ from app.dependencies import get_db
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/", response_model=List[ProposalSchema])
|
||||
async def get_proposals(db: Session = Depends(get_db)):
|
||||
return db.query(ProposalModel).all()
|
||||
return db.query(ProposalModel).all()
|
||||
|
@ -2,8 +2,21 @@ from fastapi import APIRouter, HTTPException, status, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
import uuid
|
||||
from app.schemas import Puck as PuckSchema, PuckCreate, PuckUpdate, SetTellPosition, PuckEvent
|
||||
from app.models import Puck as PuckModel, Sample as SampleModel, PuckEvent as PuckEventModel, Slot as SlotModel, LogisticsEvent as LogisticsEventModel, Dewar as DewarModel
|
||||
from app.schemas import (
|
||||
Puck as PuckSchema,
|
||||
PuckCreate,
|
||||
PuckUpdate,
|
||||
SetTellPosition,
|
||||
PuckEvent,
|
||||
)
|
||||
from app.models import (
|
||||
Puck as PuckModel,
|
||||
Sample as SampleModel,
|
||||
PuckEvent as PuckEventModel,
|
||||
Slot as SlotModel,
|
||||
LogisticsEvent as LogisticsEventModel,
|
||||
Dewar as DewarModel,
|
||||
)
|
||||
from app.dependencies import get_db
|
||||
from datetime import datetime
|
||||
import logging
|
||||
@ -13,6 +26,7 @@ router = APIRouter()
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@router.get("/", response_model=List[PuckSchema])
|
||||
async def get_pucks(db: Session = Depends(get_db)):
|
||||
return db.query(PuckModel).all()
|
||||
@ -35,8 +49,7 @@ async def get_pucks_with_tell_position(db: Session = Depends(get_db)):
|
||||
if not pucks:
|
||||
logger.info("No pucks with tell_position found.") # Log for debugging
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="No pucks with a `tell_position` found."
|
||||
status_code=404, detail="No pucks with a `tell_position` found."
|
||||
)
|
||||
|
||||
result = []
|
||||
@ -67,6 +80,7 @@ async def get_pucks_with_tell_position(db: Session = Depends(get_db)):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/{puck_id}", response_model=PuckSchema)
|
||||
async def get_puck(puck_id: str, db: Session = Depends(get_db)):
|
||||
puck = db.query(PuckModel).filter(PuckModel.id == puck_id).first()
|
||||
@ -77,13 +91,13 @@ async def get_puck(puck_id: str, db: Session = Depends(get_db)):
|
||||
|
||||
@router.post("/", response_model=PuckSchema, status_code=status.HTTP_201_CREATED)
|
||||
async def create_puck(puck: PuckCreate, db: Session = Depends(get_db)) -> PuckSchema:
|
||||
puck_id = f'PUCK-{uuid.uuid4().hex[:8].upper()}'
|
||||
puck_id = f"PUCK-{uuid.uuid4().hex[:8].upper()}"
|
||||
db_puck = PuckModel(
|
||||
id=puck_id,
|
||||
puck_name=puck.puck_name,
|
||||
puck_type=puck.puck_type,
|
||||
puck_location_in_dewar=puck.puck_location_in_dewar,
|
||||
dewar_id=puck.dewar_id
|
||||
dewar_id=puck.dewar_id,
|
||||
)
|
||||
db.add(db_puck)
|
||||
db.commit()
|
||||
@ -92,7 +106,9 @@ async def create_puck(puck: PuckCreate, db: Session = Depends(get_db)) -> PuckSc
|
||||
|
||||
|
||||
@router.put("/{puck_id}", response_model=PuckSchema)
|
||||
async def update_puck(puck_id: str, updated_puck: PuckUpdate, db: Session = Depends(get_db)):
|
||||
async def update_puck(
|
||||
puck_id: str, updated_puck: PuckUpdate, db: Session = Depends(get_db)
|
||||
):
|
||||
puck = db.query(PuckModel).filter(PuckModel.id == puck_id).first()
|
||||
if not puck:
|
||||
raise HTTPException(status_code=404, detail="Puck not found")
|
||||
@ -115,17 +131,18 @@ async def delete_puck(puck_id: str, db: Session = Depends(get_db)):
|
||||
db.commit()
|
||||
return
|
||||
|
||||
|
||||
@router.put("/{puck_id}/tell_position", status_code=status.HTTP_200_OK)
|
||||
async def set_tell_position(
|
||||
puck_id: int,
|
||||
request: SetTellPosition,
|
||||
db: Session = Depends(get_db)
|
||||
puck_id: int, request: SetTellPosition, db: Session = Depends(get_db)
|
||||
):
|
||||
# Get the requested tell_position
|
||||
tell_position = request.tell_position
|
||||
|
||||
# Define valid positions
|
||||
valid_positions = [f"{letter}{num}" for letter in "ABCDEF" for num in range(1, 6)] + ["null", None]
|
||||
valid_positions = [
|
||||
f"{letter}{num}" for letter in "ABCDEF" for num in range(1, 6)
|
||||
] + ["null", None]
|
||||
|
||||
# Validate tell_position
|
||||
if tell_position not in valid_positions:
|
||||
@ -161,7 +178,10 @@ async def get_last_tell_position(puck_id: str, db: Session = Depends(get_db)):
|
||||
# Query the most recent tell_position_set event for the given puck_id
|
||||
last_event = (
|
||||
db.query(PuckEventModel)
|
||||
.filter(PuckEventModel.puck_id == puck_id, PuckEventModel.event_type == "tell_position_set")
|
||||
.filter(
|
||||
PuckEventModel.puck_id == puck_id,
|
||||
PuckEventModel.event_type == "tell_position_set",
|
||||
)
|
||||
.order_by(PuckEventModel.timestamp.desc())
|
||||
.first()
|
||||
)
|
||||
@ -182,10 +202,7 @@ async def get_last_tell_position(puck_id: str, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.get("/slot/{slot_identifier}", response_model=List[dict])
|
||||
async def get_pucks_by_slot(
|
||||
slot_identifier: str,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db)):
|
||||
"""
|
||||
Retrieve all pucks associated with all dewars linked to the given slot
|
||||
(by ID or keyword) via 'beamline' events.
|
||||
@ -200,28 +217,29 @@ async def get_pucks_by_slot(
|
||||
"PXIII": 49,
|
||||
"X06SA": 47,
|
||||
"X10SA": 48,
|
||||
"X06DA": 49
|
||||
"X06DA": 49,
|
||||
}
|
||||
|
||||
# Check if the slot identifier is an alias or ID
|
||||
try:
|
||||
slot_id = int(slot_identifier) # If the user provided a numeric ID
|
||||
alias = next((k for k, v in slot_aliases.items() if v == slot_id), slot_identifier)
|
||||
alias = next(
|
||||
(k for k, v in slot_aliases.items() if v == slot_id), slot_identifier
|
||||
)
|
||||
except ValueError:
|
||||
slot_id = slot_aliases.get(slot_identifier.upper()) # Try mapping alias
|
||||
alias = slot_identifier.upper() # Keep alias as-is for error messages
|
||||
if not slot_id:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Invalid slot identifier. Must be an ID or one of the following: PXI, PXII, PXIII, X06SA, X10SA, X06DA."
|
||||
detail="Invalid slot identifier. Must be an ID or one of the following: PXI, PXII, PXIII, X06SA, X10SA, X06DA.",
|
||||
)
|
||||
|
||||
# Verify that the slot exists
|
||||
slot = db.query(SlotModel).filter(SlotModel.id == slot_id).first()
|
||||
if not slot:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Slot not found for identifier '{alias}'."
|
||||
status_code=404, detail=f"Slot not found for identifier '{alias}'."
|
||||
)
|
||||
|
||||
logger.info(f"Slot found: ID={slot.id}, Label={slot.label}")
|
||||
@ -231,7 +249,7 @@ async def get_pucks_by_slot(
|
||||
db.query(LogisticsEventModel)
|
||||
.filter(
|
||||
LogisticsEventModel.slot_id == slot_id,
|
||||
LogisticsEventModel.event_type == "beamline"
|
||||
LogisticsEventModel.event_type == "beamline",
|
||||
)
|
||||
.order_by(LogisticsEventModel.timestamp.desc())
|
||||
.all()
|
||||
@ -240,8 +258,7 @@ async def get_pucks_by_slot(
|
||||
if not beamline_events:
|
||||
logger.warning(f"No dewars associated to this beamline '{alias}'.")
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"No dewars found for the given beamline '{alias}'."
|
||||
status_code=404, detail=f"No dewars found for the given beamline '{alias}'."
|
||||
)
|
||||
|
||||
logger.info(f"Found {len(beamline_events)} beamline events for slot_id={slot_id}.")
|
||||
@ -253,8 +270,7 @@ async def get_pucks_by_slot(
|
||||
if not dewars:
|
||||
logger.warning(f"No dewars found for beamline '{alias}'.")
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"No dewars found for beamline '{alias}'."
|
||||
status_code=404, detail=f"No dewars found for beamline '{alias}'."
|
||||
)
|
||||
|
||||
logger.info(f"Found {len(dewars)} dewars for beamline '{alias}'.")
|
||||
@ -273,7 +289,7 @@ async def get_pucks_by_slot(
|
||||
logger.warning(f"No pucks found for dewars associated with beamline '{alias}'.")
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"No pucks found for dewars associated with beamline '{alias}'."
|
||||
detail=f"No pucks found for dewars associated with beamline '{alias}'.",
|
||||
)
|
||||
|
||||
logger.info(f"Found {len(puck_list)} pucks for beamline '{alias}'.")
|
||||
@ -285,10 +301,10 @@ async def get_pucks_by_slot(
|
||||
"puck_name": puck.puck_name,
|
||||
"puck_type": puck.puck_type,
|
||||
"dewar_id": puck.dewar_id,
|
||||
"dewar_name": dewar_mapping.get(puck.dewar_id) # Link dewar_name
|
||||
"dewar_name": dewar_mapping.get(puck.dewar_id), # Link dewar_name
|
||||
}
|
||||
for puck in puck_list
|
||||
]
|
||||
|
||||
# Return the list of pucks with their associated dewar names
|
||||
return puck_output
|
||||
return puck_output
|
||||
|
@ -2,7 +2,11 @@ from fastapi import APIRouter, HTTPException, status, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from app.schemas import Puck as PuckSchema, Sample as SampleSchema, SampleEventCreate
|
||||
from app.models import Puck as PuckModel, Sample as SampleModel, SampleEvent as SampleEventModel
|
||||
from app.models import (
|
||||
Puck as PuckModel,
|
||||
Sample as SampleModel,
|
||||
SampleEvent as SampleEventModel,
|
||||
)
|
||||
from app.dependencies import get_db
|
||||
import logging
|
||||
|
||||
@ -18,10 +22,15 @@ async def get_samples_with_events(puck_id: str, db: Session = Depends(get_db)):
|
||||
samples = db.query(SampleModel).filter(SampleModel.puck_id == puck_id).all()
|
||||
|
||||
for sample in samples:
|
||||
sample.events = db.query(SampleEventModel).filter(SampleEventModel.sample_id == sample.id).all()
|
||||
sample.events = (
|
||||
db.query(SampleEventModel)
|
||||
.filter(SampleEventModel.sample_id == sample.id)
|
||||
.all()
|
||||
)
|
||||
|
||||
return samples
|
||||
|
||||
|
||||
@router.get("/pucks-samples", response_model=List[PuckSchema])
|
||||
async def get_all_pucks_with_samples_and_events(db: Session = Depends(get_db)):
|
||||
logging.info("Fetching all pucks with samples and events")
|
||||
@ -32,5 +41,7 @@ async def get_all_pucks_with_samples_and_events(db: Session = Depends(get_db)):
|
||||
logging.info(f"Puck ID: {puck.id}, Name: {puck.puck_name}")
|
||||
|
||||
if not pucks:
|
||||
raise HTTPException(status_code=404, detail="No pucks found in the database") # More descriptive
|
||||
raise HTTPException(
|
||||
status_code=404, detail="No pucks found in the database"
|
||||
) # More descriptive
|
||||
return pucks
|
||||
|
@ -6,10 +6,27 @@ from pydantic import BaseModel, ValidationError
|
||||
from datetime import date
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from app.models import Shipment as ShipmentModel, ContactPerson as ContactPersonModel, Address as AddressModel, \
|
||||
Proposal as ProposalModel, Dewar as DewarModel, Puck as PuckModel, Sample as SampleModel
|
||||
from app.schemas import ShipmentCreate, UpdateShipmentComments, Shipment as ShipmentSchema, DewarUpdate, \
|
||||
ContactPerson as ContactPersonSchema, Sample as SampleSchema, DewarCreate, PuckCreate, SampleCreate, DewarSchema
|
||||
from app.models import (
|
||||
Shipment as ShipmentModel,
|
||||
ContactPerson as ContactPersonModel,
|
||||
Address as AddressModel,
|
||||
Proposal as ProposalModel,
|
||||
Dewar as DewarModel,
|
||||
Puck as PuckModel,
|
||||
Sample as SampleModel,
|
||||
)
|
||||
from app.schemas import (
|
||||
ShipmentCreate,
|
||||
UpdateShipmentComments,
|
||||
Shipment as ShipmentSchema,
|
||||
DewarUpdate,
|
||||
ContactPerson as ContactPersonSchema,
|
||||
Sample as SampleSchema,
|
||||
DewarCreate,
|
||||
PuckCreate,
|
||||
SampleCreate,
|
||||
DewarSchema,
|
||||
)
|
||||
from app.database import get_db
|
||||
from app.crud import get_shipments, get_shipment_by_id
|
||||
|
||||
@ -23,7 +40,9 @@ def default_serializer(obj):
|
||||
|
||||
|
||||
@router.get("", response_model=List[ShipmentSchema])
|
||||
async def fetch_shipments(id: Optional[int] = Query(None), db: Session = Depends(get_db)):
|
||||
async def fetch_shipments(
|
||||
id: Optional[int] = Query(None), db: Session = Depends(get_db)
|
||||
):
|
||||
if id:
|
||||
shipment = get_shipment_by_id(db, id)
|
||||
if not shipment:
|
||||
@ -35,9 +54,12 @@ async def fetch_shipments(id: Optional[int] = Query(None), db: Session = Depends
|
||||
shipments = get_shipments(db)
|
||||
logging.info(f"Total shipments fetched: {len(shipments)}")
|
||||
for shipment in shipments:
|
||||
logging.info(f"Shipment ID: {shipment.id}, Shipment Name: {shipment.shipment_name}")
|
||||
logging.info(
|
||||
f"Shipment ID: {shipment.id}, Shipment Name: {shipment.shipment_name}"
|
||||
)
|
||||
return shipments
|
||||
|
||||
|
||||
@router.get("/{shipment_id}/dewars", response_model=List[DewarSchema])
|
||||
async def get_dewars_by_shipment_id(shipment_id: int, db: Session = Depends(get_db)):
|
||||
shipment = db.query(ShipmentModel).filter(ShipmentModel.id == shipment_id).first()
|
||||
@ -51,12 +73,21 @@ async def get_dewars_by_shipment_id(shipment_id: int, db: Session = Depends(get_
|
||||
return dewars
|
||||
|
||||
|
||||
|
||||
@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()
|
||||
return_address = db.query(AddressModel).filter(AddressModel.id == shipment.return_address_id).first()
|
||||
proposal = db.query(ProposalModel).filter(ProposalModel.id == shipment.proposal_id).first()
|
||||
contact_person = (
|
||||
db.query(ContactPersonModel)
|
||||
.filter(ContactPersonModel.id == shipment.contact_person_id)
|
||||
.first()
|
||||
)
|
||||
return_address = (
|
||||
db.query(AddressModel)
|
||||
.filter(AddressModel.id == shipment.return_address_id)
|
||||
.first()
|
||||
)
|
||||
proposal = (
|
||||
db.query(ProposalModel).filter(ProposalModel.id == shipment.proposal_id).first()
|
||||
)
|
||||
|
||||
if not (contact_person or return_address or proposal):
|
||||
raise HTTPException(status_code=404, detail="Associated entity not found")
|
||||
@ -97,17 +128,29 @@ async def delete_shipment(shipment_id: int, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.put("/{shipment_id}", response_model=ShipmentSchema)
|
||||
async def update_shipment(shipment_id: int, updated_shipment: ShipmentCreate, db: Session = Depends(get_db)):
|
||||
print("Received payload:", json.dumps(updated_shipment.dict(), indent=2, default=default_serializer))
|
||||
async def update_shipment(
|
||||
shipment_id: int, updated_shipment: ShipmentCreate, db: Session = Depends(get_db)
|
||||
):
|
||||
print(
|
||||
"Received payload:",
|
||||
json.dumps(updated_shipment.dict(), indent=2, default=default_serializer),
|
||||
)
|
||||
|
||||
shipment = db.query(ShipmentModel).filter(ShipmentModel.id == shipment_id).first()
|
||||
if not shipment:
|
||||
raise HTTPException(status_code=404, detail="Shipment not found")
|
||||
|
||||
# Validate relationships by IDs
|
||||
contact_person = db.query(ContactPersonModel).filter(
|
||||
ContactPersonModel.id == updated_shipment.contact_person_id).first()
|
||||
return_address = db.query(AddressModel).filter(AddressModel.id == updated_shipment.return_address_id).first()
|
||||
contact_person = (
|
||||
db.query(ContactPersonModel)
|
||||
.filter(ContactPersonModel.id == updated_shipment.contact_person_id)
|
||||
.first()
|
||||
)
|
||||
return_address = (
|
||||
db.query(AddressModel)
|
||||
.filter(AddressModel.id == updated_shipment.return_address_id)
|
||||
.first()
|
||||
)
|
||||
if not contact_person:
|
||||
raise HTTPException(status_code=404, detail="Contact person not found")
|
||||
if not return_address:
|
||||
@ -123,25 +166,39 @@ async def update_shipment(shipment_id: int, updated_shipment: ShipmentCreate, db
|
||||
|
||||
# Process and update dewars' details
|
||||
for dewar_data in updated_shipment.dewars:
|
||||
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_data.dewar_id).first()
|
||||
dewar = (
|
||||
db.query(DewarModel).filter(DewarModel.id == dewar_data.dewar_id).first()
|
||||
)
|
||||
if not dewar:
|
||||
raise HTTPException(status_code=404, detail=f"Dewar with ID {dewar_data.dewar_id} not found")
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"Dewar with ID {dewar_data.dewar_id} not found"
|
||||
)
|
||||
|
||||
update_fields = dewar_data.dict(exclude_unset=True)
|
||||
for key, value in update_fields.items():
|
||||
if key == 'contact_person_id':
|
||||
contact_person = db.query(ContactPersonModel).filter(ContactPersonModel.id == value).first()
|
||||
if key == "contact_person_id":
|
||||
contact_person = (
|
||||
db.query(ContactPersonModel)
|
||||
.filter(ContactPersonModel.id == value)
|
||||
.first()
|
||||
)
|
||||
if not contact_person:
|
||||
raise HTTPException(status_code=404,
|
||||
detail=f"Contact person with ID {value} for Dewar {dewar_data.dewar_id} not found")
|
||||
if key == 'return_address_id':
|
||||
address = db.query(AddressModel).filter(AddressModel.id == value).first()
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Contact person with ID {value} for Dewar {dewar_data.dewar_id} not found",
|
||||
)
|
||||
if key == "return_address_id":
|
||||
address = (
|
||||
db.query(AddressModel).filter(AddressModel.id == value).first()
|
||||
)
|
||||
if not address:
|
||||
raise HTTPException(status_code=404,
|
||||
detail=f"Address with ID {value} for Dewar {dewar_data.dewar_id} not found")
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Address with ID {value} for Dewar {dewar_data.dewar_id} not found",
|
||||
)
|
||||
|
||||
for key, value in update_fields.items():
|
||||
if key != 'dewar_id':
|
||||
if key != "dewar_id":
|
||||
setattr(dewar, key, value)
|
||||
|
||||
db.commit()
|
||||
@ -150,7 +207,9 @@ async def update_shipment(shipment_id: int, updated_shipment: ShipmentCreate, db
|
||||
|
||||
|
||||
@router.post("/{shipment_id}/add_dewar", response_model=ShipmentSchema)
|
||||
async def add_dewar_to_shipment(shipment_id: int, dewar_id: int, db: Session = Depends(get_db)):
|
||||
async def add_dewar_to_shipment(
|
||||
shipment_id: int, dewar_id: int, 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")
|
||||
@ -166,14 +225,18 @@ async def add_dewar_to_shipment(shipment_id: int, dewar_id: int, db: Session = D
|
||||
|
||||
|
||||
@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)):
|
||||
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()
|
||||
if not shipment:
|
||||
raise HTTPException(status_code=404, detail="Shipment not found")
|
||||
|
||||
dewar_exists = any(dw.id == dewar_id for dw in shipment.dewars)
|
||||
if not dewar_exists:
|
||||
raise HTTPException(status_code=404, detail=f"Dewar with ID {dewar_id} not found in shipment")
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"Dewar with ID {dewar_id} not found in shipment"
|
||||
)
|
||||
|
||||
shipment.dewars = [dw for dw in shipment.dewars if dw.id != dewar_id]
|
||||
db.commit()
|
||||
@ -201,8 +264,13 @@ async def get_samples_in_shipment(shipment_id: int, db: Session = Depends(get_db
|
||||
return samples
|
||||
|
||||
|
||||
@router.get("/shipments/{shipment_id}/dewars/{dewar_id}/samples", response_model=List[SampleSchema])
|
||||
async def get_samples_in_dewar(shipment_id: int, dewar_id: int, db: Session = Depends(get_db)):
|
||||
@router.get(
|
||||
"/shipments/{shipment_id}/dewars/{dewar_id}/samples",
|
||||
response_model=List[SampleSchema],
|
||||
)
|
||||
async 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")
|
||||
@ -220,8 +288,11 @@ async def get_samples_in_dewar(shipment_id: int, dewar_id: int, db: Session = De
|
||||
|
||||
|
||||
@router.put("/{shipment_id}/comments", response_model=ShipmentSchema)
|
||||
async def update_shipment_comments(shipment_id: int, comments_data: UpdateShipmentComments,
|
||||
db: Session = Depends(get_db)):
|
||||
async def update_shipment_comments(
|
||||
shipment_id: int,
|
||||
comments_data: UpdateShipmentComments,
|
||||
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")
|
||||
@ -232,15 +303,25 @@ async def update_shipment_comments(shipment_id: int, comments_data: UpdateShipme
|
||||
return shipment
|
||||
|
||||
|
||||
@router.post("/{shipment_id}/add_dewar_puck_sample", response_model=ShipmentSchema, status_code=status.HTTP_201_CREATED)
|
||||
def add_dewar_puck_sample_to_shipment(shipment_id: int, payload: DewarCreate, db: Session = Depends(get_db)):
|
||||
@router.post(
|
||||
"/{shipment_id}/add_dewar_puck_sample",
|
||||
response_model=ShipmentSchema,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
)
|
||||
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")
|
||||
|
||||
try:
|
||||
for dewar_data in payload.dewars:
|
||||
dewar = db.query(DewarModel).filter(DewarModel.dewar_name == dewar_data.dewar_name).first()
|
||||
dewar = (
|
||||
db.query(DewarModel)
|
||||
.filter(DewarModel.dewar_name == dewar_data.dewar_name)
|
||||
.first()
|
||||
)
|
||||
if dewar:
|
||||
# Update existing dewar
|
||||
dewar.tracking_number = dewar_data.tracking_number
|
||||
@ -284,4 +365,4 @@ def add_dewar_puck_sample_to_shipment(shipment_id: int, payload: DewarCreate, db
|
||||
except ValidationError as e:
|
||||
raise HTTPException(status_code=400, detail=f"Validation error: {e}")
|
||||
|
||||
return shipment
|
||||
return shipment
|
||||
|
@ -1,7 +1,10 @@
|
||||
from app.sample_models import SpreadsheetModel, SpreadsheetResponse
|
||||
from fastapi import APIRouter, UploadFile, File, HTTPException
|
||||
import logging
|
||||
from app.services.spreadsheet_service import SampleSpreadsheetImporter, SpreadsheetImportError
|
||||
from app.services.spreadsheet_service import (
|
||||
SampleSpreadsheetImporter,
|
||||
SpreadsheetImportError,
|
||||
)
|
||||
from fastapi.responses import FileResponse
|
||||
import os
|
||||
from pydantic import ValidationError # Import ValidationError here
|
||||
@ -10,20 +13,27 @@ from app.row_storage import row_storage # Import the RowStorage instance
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
importer = SampleSpreadsheetImporter() # assuming this is a singleton or manageable instance
|
||||
importer = (
|
||||
SampleSpreadsheetImporter()
|
||||
) # assuming this is a singleton or manageable instance
|
||||
|
||||
|
||||
@router.get("/download-template", response_class=FileResponse)
|
||||
async def download_template():
|
||||
"""Serve a template file for spreadsheet upload."""
|
||||
current_dir = os.path.dirname(__file__)
|
||||
template_path = os.path.join(current_dir, "../../downloads/V7_TELLSamplesSpreadsheetTemplate.xlsx")
|
||||
template_path = os.path.join(
|
||||
current_dir, "../../downloads/V7_TELLSamplesSpreadsheetTemplate.xlsx"
|
||||
)
|
||||
|
||||
if not os.path.exists(template_path):
|
||||
raise HTTPException(status_code=404, detail="Template file not found.")
|
||||
|
||||
return FileResponse(template_path, filename="template.xlsx",
|
||||
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
return FileResponse(
|
||||
template_path,
|
||||
filename="template.xlsx",
|
||||
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
)
|
||||
|
||||
|
||||
@router.post("/upload", response_model=SpreadsheetResponse)
|
||||
@ -33,17 +43,24 @@ async def upload_file(file: UploadFile = File(...)):
|
||||
logger.info(f"Received file: {file.filename}")
|
||||
|
||||
# Validate file format
|
||||
if not file.filename.endswith('.xlsx'):
|
||||
if not file.filename.endswith(".xlsx"):
|
||||
logger.error("Invalid file format")
|
||||
raise HTTPException(status_code=400, detail="Invalid file format. Please upload an .xlsx file.")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Invalid file format. Please upload an .xlsx file.",
|
||||
)
|
||||
|
||||
# Initialize the importer and process the spreadsheet
|
||||
validated_model, errors, raw_data, headers = importer.import_spreadsheet_with_errors(file)
|
||||
validated_model, errors, raw_data, headers = (
|
||||
importer.import_spreadsheet_with_errors(file)
|
||||
)
|
||||
|
||||
# Extract unique values for dewars, pucks, and samples
|
||||
dewars = {sample.dewarname for sample in validated_model if sample.dewarname}
|
||||
pucks = {sample.puckname for sample in validated_model if sample.puckname}
|
||||
samples = {sample.crystalname for sample in validated_model if sample.crystalname}
|
||||
samples = {
|
||||
sample.crystalname for sample in validated_model if sample.crystalname
|
||||
}
|
||||
|
||||
# Construct the response model with the processed data
|
||||
response_data = SpreadsheetResponse(
|
||||
@ -56,7 +73,7 @@ async def upload_file(file: UploadFile = File(...)):
|
||||
pucks=list(pucks),
|
||||
samples_count=len(samples),
|
||||
samples=list(samples),
|
||||
headers=headers # Include headers in the response
|
||||
headers=headers, # Include headers in the response
|
||||
)
|
||||
|
||||
# Store row data for future use
|
||||
@ -64,16 +81,23 @@ async def upload_file(file: UploadFile = File(...)):
|
||||
row_num = idx + 4 # Adjust row numbering if necessary
|
||||
row_storage.set_row(row_num, row.dict())
|
||||
|
||||
logger.info(f"Returning response with {len(validated_model)} records and {len(errors)} errors.")
|
||||
logger.info(
|
||||
f"Returning response with {len(validated_model)} records and {len(errors)} errors."
|
||||
)
|
||||
return response_data
|
||||
|
||||
except SpreadsheetImportError as e:
|
||||
logger.error(f"Spreadsheet import error: {str(e)}")
|
||||
raise HTTPException(status_code=400, detail=f"Error processing spreadsheet: {str(e)}")
|
||||
raise HTTPException(
|
||||
status_code=400, detail=f"Error processing spreadsheet: {str(e)}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected error occurred: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to upload file. Please try again. Error: {str(e)}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to upload file. Please try again. Error: {str(e)}",
|
||||
)
|
||||
|
||||
|
||||
@router.post("/validate-cell")
|
||||
@ -86,7 +110,9 @@ async def validate_cell(data: dict):
|
||||
current_row_data = row_storage.get_row(row_num)
|
||||
|
||||
# Update the cell value
|
||||
current_row_data[col_name] = importer._clean_value(value, importer.get_expected_type(col_name))
|
||||
current_row_data[col_name] = importer._clean_value(
|
||||
value, importer.get_expected_type(col_name)
|
||||
)
|
||||
|
||||
# Temporarily store the updated row data
|
||||
row_storage.set_row(row_num, current_row_data)
|
||||
@ -100,6 +126,8 @@ async def validate_cell(data: dict):
|
||||
return {"is_valid": True, "message": ""}
|
||||
except ValidationError as e:
|
||||
# Extract the first error message
|
||||
message = e.errors()[0]['msg']
|
||||
logger.error(f"Validation failed for row {row_num}, column {col_name}: {message}")
|
||||
message = e.errors()[0]["msg"]
|
||||
logger.error(
|
||||
f"Validation failed for row {row_num}, column {col_name}: {message}"
|
||||
)
|
||||
return {"is_valid": False, "message": message}
|
||||
|
Reference in New Issue
Block a user