提交
This commit is contained in:
1 parent
493f8d6756
commit
d84f4b944c
406 files changed
+58954
-10376
No files matched your search
@@ -1,4 +1,5 @@
|
||||
"""运输计划管理 - 基础数据 API(承运商、车辆、人员)"""
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
@@ -7,6 +8,7 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.core.db_auth import DbUserContext, get_db_current_user
|
||||
from app.core.delete_guard import assert_row_deletable_by_creator, user_info_from_context
|
||||
from app.services.pl_data_scope import apply_pl_scope, assert_pl_row_in_scope
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.core.utils import generate_uuid
|
||||
@@ -18,9 +20,11 @@ from app.models.pl_models import (
|
||||
PlVehiclePersonnel,
|
||||
)
|
||||
from app.schemas.pl import (
|
||||
CarrierAuditReject,
|
||||
CarrierCreate,
|
||||
CarrierRead,
|
||||
CarrierUpdate,
|
||||
carrier_to_read,
|
||||
DriverCreate,
|
||||
DriverRead,
|
||||
DriverUpdate,
|
||||
@@ -40,6 +44,10 @@ from app.services.pl_cert_service import (
|
||||
nearest_expire_date,
|
||||
save_owner_certs,
|
||||
)
|
||||
from app.services.pl_carrier_service import (
|
||||
carrier_eligible_for_transport,
|
||||
carrier_qualification_complete,
|
||||
)
|
||||
from app.services.pl_personnel_service import (
|
||||
load_vehicle_personnel_rows,
|
||||
load_vehicle_personnel_summaries,
|
||||
@@ -58,6 +66,7 @@ router = APIRouter(prefix="", tags=["运输计划-基础数据"])
|
||||
def list_carriers(
|
||||
q: Optional[str] = Query(default=None, description="模糊搜索"),
|
||||
status: Optional[str] = Query(default=None, description="状态"),
|
||||
audit_status: Optional[str] = Query(default=None, alias="auditStatus", description="审核状态"),
|
||||
db: Session = Depends(get_db),
|
||||
user: DbUserContext = Depends(get_db_current_user),
|
||||
) -> list[CarrierRead]:
|
||||
@@ -70,6 +79,9 @@ def list_carriers(
|
||||
if status:
|
||||
query = query.filter(PlCarrier.status == status)
|
||||
|
||||
if audit_status:
|
||||
query = query.filter(PlCarrier.audit_status == audit_status)
|
||||
|
||||
if q:
|
||||
query = query.filter(
|
||||
or_(
|
||||
@@ -84,7 +96,7 @@ def list_carriers(
|
||||
case((PlCarrier.order_num.is_(None), 1), else_=0).asc(),
|
||||
PlCarrier.create_time.desc(),
|
||||
)
|
||||
return query.all()
|
||||
return [carrier_to_read(row) for row in query.all()]
|
||||
|
||||
|
||||
@router.post("/carrier", response_model=CarrierRead, status_code=status.HTTP_201_CREATED)
|
||||
@@ -102,6 +114,11 @@ def create_carrier(
|
||||
contact_name=payload.contact_name,
|
||||
contact_phone=payload.contact_phone,
|
||||
status=payload.status,
|
||||
business_license_urls=payload.business_license_urls.strip(),
|
||||
road_transport_license_urls=payload.road_transport_license_urls.strip(),
|
||||
transport_agreement_urls=payload.transport_agreement_urls.strip(),
|
||||
transport_agreement_expire_date=payload.transport_agreement_expire_date,
|
||||
audit_status="pending",
|
||||
remark=payload.remark,
|
||||
create_by=user.id,
|
||||
create_dept_id=user.dept_id,
|
||||
@@ -109,7 +126,7 @@ def create_carrier(
|
||||
db.add(carrier)
|
||||
db.commit()
|
||||
db.refresh(carrier)
|
||||
return carrier
|
||||
return carrier_to_read(carrier)
|
||||
|
||||
|
||||
@router.get("/carrier/{id}", response_model=CarrierRead)
|
||||
@@ -120,7 +137,7 @@ def get_carrier(
|
||||
) -> CarrierRead:
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
carrier = _get_carrier(db, tenant_no, id, user)
|
||||
return carrier
|
||||
return carrier_to_read(carrier)
|
||||
|
||||
|
||||
@router.put("/carrier/{id}", response_model=CarrierRead)
|
||||
@@ -133,13 +150,28 @@ def update_carrier(
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
carrier = _get_carrier(db, tenant_no, id, user)
|
||||
|
||||
for key, value in payload.model_dump(exclude_unset=True).items():
|
||||
payload_data = payload.model_dump(exclude_unset=True)
|
||||
qual_keys = (
|
||||
"business_license_urls",
|
||||
"road_transport_license_urls",
|
||||
"transport_agreement_urls",
|
||||
"transport_agreement_expire_date",
|
||||
)
|
||||
qual_changed = any(key in payload_data for key in qual_keys)
|
||||
|
||||
for key, value in payload_data.items():
|
||||
setattr(carrier, key, value)
|
||||
|
||||
if qual_changed and carrier.audit_status == "approved":
|
||||
carrier.audit_status = "pending"
|
||||
carrier.audit_by = None
|
||||
carrier.audit_time = None
|
||||
carrier.audit_remark = None
|
||||
|
||||
carrier.update_by = user.id
|
||||
db.commit()
|
||||
db.refresh(carrier)
|
||||
return carrier
|
||||
return carrier_to_read(carrier)
|
||||
|
||||
|
||||
@router.delete("/carrier/{id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
@@ -150,11 +182,59 @@ def delete_carrier(
|
||||
) -> None:
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
carrier = _get_carrier(db, tenant_no, id, user)
|
||||
assert_row_deletable_by_creator(carrier, user_info_from_context(user))
|
||||
carrier.del_flag = 1
|
||||
carrier.update_by = user.id
|
||||
db.commit()
|
||||
|
||||
|
||||
@router.post("/carrier/{id}/approve", response_model=CarrierRead)
|
||||
def approve_carrier(
|
||||
id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: DbUserContext = Depends(get_db_current_user),
|
||||
) -> CarrierRead:
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
carrier = _get_carrier(db, tenant_no, id, user)
|
||||
|
||||
if carrier.audit_status == "approved":
|
||||
raise HTTPException(status_code=400, detail="承运商已审核通过")
|
||||
if not carrier_qualification_complete(carrier):
|
||||
raise HTTPException(status_code=400, detail="承运商资质附件不完整,无法审核通过")
|
||||
|
||||
carrier.audit_status = "approved"
|
||||
carrier.audit_by = user.id
|
||||
carrier.audit_time = datetime.now()
|
||||
carrier.audit_remark = None
|
||||
carrier.update_by = user.id
|
||||
db.commit()
|
||||
db.refresh(carrier)
|
||||
return carrier_to_read(carrier)
|
||||
|
||||
|
||||
@router.post("/carrier/{id}/reject", response_model=CarrierRead)
|
||||
def reject_carrier(
|
||||
id: str,
|
||||
payload: CarrierAuditReject,
|
||||
db: Session = Depends(get_db),
|
||||
user: DbUserContext = Depends(get_db_current_user),
|
||||
) -> CarrierRead:
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
carrier = _get_carrier(db, tenant_no, id, user)
|
||||
|
||||
if carrier.audit_status == "approved":
|
||||
raise HTTPException(status_code=400, detail="承运商已审核通过,无法驳回")
|
||||
|
||||
carrier.audit_status = "rejected"
|
||||
carrier.audit_by = user.id
|
||||
carrier.audit_time = datetime.now()
|
||||
carrier.audit_remark = (payload.remark or "").strip() or None
|
||||
carrier.update_by = user.id
|
||||
db.commit()
|
||||
db.refresh(carrier)
|
||||
return carrier_to_read(carrier)
|
||||
|
||||
|
||||
def _get_carrier(db: Session, tenant_no: str, carrier_id: str, user: DbUserContext) -> PlCarrier:
|
||||
carrier = (
|
||||
db.query(PlCarrier)
|
||||
@@ -212,6 +292,11 @@ def list_vehicles(
|
||||
vehicle_type: Optional[str] = Query(default=None, alias="vehicleType", description="车辆类型"),
|
||||
carrier_id: Optional[str] = Query(default=None, alias="carrierId", description="承运商ID"),
|
||||
vehicle_status: Optional[str] = Query(default=None, alias="vehicleStatus", description="车辆状态"),
|
||||
exclude_ineligible_carrier: Optional[bool] = Query(
|
||||
default=False,
|
||||
alias="excludeIneligibleCarrier",
|
||||
description="排除资质不全或协议过期的承运商车辆",
|
||||
),
|
||||
db: Session = Depends(get_db),
|
||||
user: DbUserContext = Depends(get_db_current_user),
|
||||
) -> list[VehicleRead]:
|
||||
@@ -240,6 +325,34 @@ def list_vehicles(
|
||||
PlVehicle.create_time.desc(),
|
||||
)
|
||||
vehicles = query.all()
|
||||
|
||||
if exclude_ineligible_carrier:
|
||||
carrier_ids = {
|
||||
v.carrier_id for v in vehicles if v.vehicle_type == "carrier" and v.carrier_id
|
||||
}
|
||||
carrier_map: dict[str, PlCarrier] = {}
|
||||
if carrier_ids:
|
||||
carriers = (
|
||||
db.query(PlCarrier)
|
||||
.filter(
|
||||
PlCarrier.id.in_(carrier_ids),
|
||||
PlCarrier.tenant_no == tenant_no,
|
||||
PlCarrier.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
carrier_map = {c.id: c for c in carriers}
|
||||
vehicles = [
|
||||
v
|
||||
for v in vehicles
|
||||
if v.vehicle_type != "carrier"
|
||||
or not v.carrier_id
|
||||
or (
|
||||
v.carrier_id in carrier_map
|
||||
and carrier_eligible_for_transport(carrier_map[v.carrier_id])
|
||||
)
|
||||
]
|
||||
|
||||
summaries = load_vehicle_personnel_summaries(
|
||||
db, tenant_no, [v.id for v in vehicles]
|
||||
)
|
||||
@@ -387,6 +500,7 @@ def delete_vehicle(
|
||||
) -> None:
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
vehicle = _get_vehicle(db, tenant_no, id, user)
|
||||
assert_row_deletable_by_creator(vehicle, user_info_from_context(user))
|
||||
vehicle.del_flag = 1
|
||||
vehicle.update_by = user.id
|
||||
db.commit()
|
||||
@@ -568,6 +682,7 @@ def delete_personnel(
|
||||
) -> None:
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
personnel = _get_personnel(db, tenant_no, id, user)
|
||||
assert_row_deletable_by_creator(personnel, user_info_from_context(user))
|
||||
personnel.del_flag = 1
|
||||
personnel.update_by = user.id
|
||||
db.commit()
|
||||
@@ -710,6 +825,7 @@ def delete_driver(
|
||||
) -> None:
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
personnel = _get_personnel(db, tenant_no, id, user)
|
||||
assert_row_deletable_by_creator(personnel, user_info_from_context(user))
|
||||
personnel.del_flag = 1
|
||||
personnel.update_by = user.id
|
||||
db.commit()
|
||||
@@ -783,5 +899,6 @@ def unbind_vehicle_driver(
|
||||
assert_pl_row_in_scope(db, vd, PlVehiclePersonnel, user, tenant_no)
|
||||
else:
|
||||
assert_pl_row_in_scope(db, vd, PlVehicleDriver, user, tenant_no)
|
||||
assert_row_deletable_by_creator(vd, user_info_from_context(user))
|
||||
vd.del_flag = 1
|
||||
db.commit()
|
||||
Reference in new issue
Block a user