import sys from fastapi import FastAPI, Request from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse from config.settings import load_settings # 加载配置文件,失败则退出 try: settings = load_settings() except FileNotFoundError as e: print(f"配置文件错误: {e}") sys.exit(1) except Exception as e: print(f"加载配置失败: {e}") sys.exit(1) from app.api.v1.location import router as location_router from app.api.v1.box import router as box_router from app.api.v1.accessory import router as accessory_router from app.services.location_service import ( AlreadyOffShelfError, DuplicateLocationError, PaichaNotFoundError, ) from app.services.box_service import ( BoxItemNotFoundError, DuplicateBoxItemError, InvalidBoxItemError, InvalidQuantityError, InvalidZongpaiError, ZongpaiNotFoundError, ) from app.services.accessory_service import ( AccessoryAlreadyBoxedError, AccessoryAlreadyOffShelfError, AccessoryDuplicateLocationError, AccessoryNotFoundError, AccessoryTypeNotFoundError, DuplicateAccessoryTypeNameError, InvalidPaichanError, PaichanNotFoundError as AccessoryPaichanNotFoundError, ) app = FastAPI(title="CargoTrace API", version="0.1.0") app.include_router(location_router, prefix="/CargoTrace") app.include_router(box_router, prefix="/CargoTrace") app.include_router(accessory_router, prefix="/CargoTrace") @app.exception_handler(DuplicateLocationError) async def duplicate_location_handler(request: Request, exc: DuplicateLocationError): return JSONResponse( status_code=409, content={ "error_code": "DUPLICATE_LOCATION", "message": "该总排号已存在货位记录", "location_code": exc.location_code, "registered_at": exc.registered_at, }, ) @app.exception_handler(AlreadyOffShelfError) async def already_off_shelf_handler(request: Request, exc: AlreadyOffShelfError): return JSONResponse( status_code=409, content={ "error_code": "ALREADY_OFF_SHELF", "message": "该总排号已下架至转运区域,不可重新上架", "location_code": exc.location_code, "registered_at": exc.registered_at, }, ) @app.exception_handler(RequestValidationError) async def validation_error_handler(request: Request, exc: RequestValidationError): for err in exc.errors(): msg = err.get("msg", "") if "INVALID_ZONGPAI" in msg or "INVALID_LOCATION" in msg or "INVALID_BOX_NO" in msg or "INVALID_QUANTITY" in msg or "INVALID_PAICHAN" in msg or "INVALID_TYPE_NAME" in msg: error_code = msg.replace("Value error, ", "") return JSONResponse( status_code=400, content={ "error_code": error_code, "message": error_code, }, ) return JSONResponse( status_code=422, content={"detail": exc.errors()}, ) @app.exception_handler(ValueError) async def value_error_handler(request: Request, exc: ValueError): error_code = str(exc) return JSONResponse( status_code=400, content={ "error_code": error_code, "message": error_code, }, ) @app.exception_handler(InvalidZongpaiError) async def invalid_zongpai_handler(request: Request, exc: InvalidZongpaiError): return JSONResponse( status_code=400, content={ "error_code": "INVALID_ZONGPAI", "message": "总排号格式不合法", }, ) @app.exception_handler(ZongpaiNotFoundError) async def zongpai_not_found_handler(request: Request, exc: ZongpaiNotFoundError): return JSONResponse( status_code=404, content={ "error_code": "ZONGPAI_NOT_FOUND", "message": "未找到该总排号对应的排产号信息", }, ) @app.exception_handler(DuplicateBoxItemError) async def duplicate_box_handler(request: Request, exc: DuplicateBoxItemError): return JSONResponse( status_code=409, content={ "error_code": "DUPLICATE_BOX_NO", "message": f"排产号 {exc.paichan_no} 下箱号 {exc.box_no} 已存在", "paichan_no": exc.paichan_no, "box_no": exc.box_no, }, ) @app.exception_handler(BoxItemNotFoundError) async def box_item_not_found_handler(request: Request, exc: BoxItemNotFoundError): return JSONResponse( status_code=404, content={ "error_code": "BOX_ITEM_NOT_FOUND", "message": "指定装箱明细不存在", }, ) @app.exception_handler(PaichaNotFoundError) async def paicha_not_found_handler(request: Request, exc: PaichaNotFoundError): return JSONResponse( status_code=404, content={ "error_code": "PAICHA_NOT_FOUND", "message": "暂无排产信息", }, ) @app.exception_handler(InvalidQuantityError) async def invalid_quantity_handler(request: Request, exc: InvalidQuantityError): return JSONResponse( status_code=400, content={ "error_code": "INVALID_QUANTITY", "message": "装箱数量超出可装数量上限", }, ) @app.exception_handler(InvalidBoxItemError) async def invalid_box_item_handler(request: Request, exc: InvalidBoxItemError): return JSONResponse( status_code=400, content={ "error_code": "INVALID_BOX_ITEM", "message": "装箱明细记录不合法或不允许修改", }, ) @app.exception_handler(InvalidPaichanError) async def invalid_paichan_handler(request: Request, exc: InvalidPaichanError): return JSONResponse( status_code=400, content={ "error_code": "INVALID_PAICHAN", "message": "排产号格式不合法", }, ) @app.exception_handler(AccessoryPaichanNotFoundError) async def accessory_paichan_not_found_handler( request: Request, exc: AccessoryPaichanNotFoundError ): return JSONResponse( status_code=404, content={ "error_code": "PAICHA_NOT_FOUND", "message": "未找到该排产号信息", }, ) @app.exception_handler(AccessoryNotFoundError) async def accessory_not_found_handler(request: Request, exc: AccessoryNotFoundError): return JSONResponse( status_code=404, content={ "error_code": "ACCESSORY_NOT_FOUND", "message": "附件记录不存在", }, ) @app.exception_handler(AccessoryAlreadyBoxedError) async def accessory_already_boxed_handler( request: Request, exc: AccessoryAlreadyBoxedError ): return JSONResponse( status_code=409, content={ "error_code": "ALREADY_BOXED", "message": "该附件已装箱不可操作", }, ) @app.exception_handler(AccessoryDuplicateLocationError) async def accessory_duplicate_location_handler( request: Request, exc: AccessoryDuplicateLocationError ): return JSONResponse( status_code=409, content={ "error_code": "DUPLICATE_LOCATION", "message": "该附件已存在货位记录", "location_code": exc.location_code, "registered_at": exc.registered_at, }, ) @app.exception_handler(AccessoryAlreadyOffShelfError) async def accessory_already_off_shelf_handler( request: Request, exc: AccessoryAlreadyOffShelfError ): return JSONResponse( status_code=409, content={ "error_code": "ALREADY_OFF_SHELF", "message": "该附件已下架不可重新上架", "location_code": exc.location_code, "registered_at": exc.registered_at, }, ) @app.exception_handler(AccessoryTypeNotFoundError) async def accessory_type_not_found_handler( request: Request, exc: AccessoryTypeNotFoundError ): return JSONResponse( status_code=404, content={ "error_code": "ACCESSORY_TYPE_NOT_FOUND", "message": "附件类型不存在", }, ) @app.exception_handler(DuplicateAccessoryTypeNameError) async def duplicate_accessory_type_name_handler( request: Request, exc: DuplicateAccessoryTypeNameError ): return JSONResponse( status_code=409, content={ "error_code": "DUPLICATE_TYPE_NAME", "message": "附件类型名称已存在", }, ) @app.get("/") async def root(): return {"message": "Welcome to CargoTrace API"}