296 lines
8.5 KiB
Python
296 lines
8.5 KiB
Python
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"}
|