This commit is contained in:
zlwu committed 2026-06-21 09:19:07 +08:00
1 parent c3be9d1dce
commit 299609706c
328 files changed
+144899 -13873

No files matched your search

+1 -1
View File
@@ -1 +1 @@
65868
17854
+9 -1
View File
@@ -52,11 +52,14 @@ def _build_details_data(db: Session, tenant_no: str, body_details) -> List[dict]
@router.get("/generate-title", response_model=ApiResponse[str])
def get_generated_title(
reimburseDate: Optional[str] = None,
excludeApplyId: Optional[str] = None,
db: Session = Depends(get_db),
user: BxUserContext = Depends(get_bx_current_user),
):
tenant_no = _tenant(db, user)
title = generate_title(db, user.name, tenant_no)
exclude_id = str(excludeApplyId).strip() if excludeApplyId else None
title = generate_title(db, user.name, tenant_no, reimburseDate, exclude_id)
return ApiResponse(data=title)
@@ -266,6 +269,7 @@ def create_reimburse(
"apply_code": generate_apply_code(db, "BX", tenant_no),
"status": "draft",
"remark": body.remark,
"reimburse_date": body.reimburse_date,
}
if body.title:
data["title"] = body.title
@@ -301,6 +305,10 @@ def update_reimburse(
main_data = {}
if body.remark is not None:
main_data["remark"] = body.remark
if body.reimburse_date is not None:
main_data["reimburse_date"] = body.reimburse_date
if body.title is not None:
main_data["title"] = body.title
reimburse = ReimburseService.update_with_details(
db, reimburse_id, main_data, details_data, user=user
)
+22
View File
@@ -0,0 +1,22 @@
"""运输计划管理 - API 路由聚合"""
from fastapi import APIRouter
from app.api.pl import plan, transport, freight, inventory
from app.api.pl import base_data
pl_router = APIRouter(prefix="/transport", tags=["运输计划管理"])
# 基础数据(承运商、车辆、司机)
pl_router.include_router(base_data.router)
# 计划管理
pl_router.include_router(plan.router)
# 运输管理
pl_router.include_router(transport.router)
# 运费结算
pl_router.include_router(freight.router)
# 盘存统计
pl_router.include_router(inventory.router)
+768
View File
@@ -0,0 +1,768 @@
"""运输计划管理 - 基础数据 API(承运商、车辆、人员)"""
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import case, func, or_
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.tenant_context import get_tenant_no
from app.core.utils import generate_uuid
from app.models.pl_models import (
PlCarrier,
PlPersonnel,
PlVehicle,
PlVehicleDriver,
PlVehiclePersonnel,
)
from app.schemas.pl import (
CarrierCreate,
CarrierRead,
CarrierUpdate,
DriverCreate,
DriverRead,
DriverUpdate,
PersonnelCreate,
PersonnelDetailRead,
PersonnelRead,
PersonnelUpdate,
VehicleCreate,
VehicleDetailRead,
VehicleDriverCreate,
VehicleRead,
VehicleUpdate,
)
from app.services.pl_cert_service import (
certs_to_read,
list_owner_certs,
nearest_expire_date,
save_owner_certs,
)
from app.services.pl_personnel_service import (
load_vehicle_personnel_rows,
load_vehicle_personnel_summaries,
save_vehicle_personnel,
)
router = APIRouter(prefix="", tags=["运输计划-基础数据"])
# =============================================================================
# 承运商 API
# =============================================================================
@router.get("/carrier", response_model=list[CarrierRead])
def list_carriers(
q: Optional[str] = Query(default=None, description="模糊搜索"),
status: Optional[str] = Query(default=None, description="状态"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> list[CarrierRead]:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlCarrier).filter(
PlCarrier.tenant_no == tenant_no,
PlCarrier.del_flag == 0,
)
if status:
query = query.filter(PlCarrier.status == status)
if q:
query = query.filter(
or_(
func.lower(PlCarrier.carrier_name).contains(q.lower()),
func.lower(PlCarrier.contact_name).contains(q.lower()),
)
)
query = query.order_by(
case((PlCarrier.order_num.is_(None), 1), else_=0).asc(),
PlCarrier.create_time.desc(),
)
return query.all()
@router.post("/carrier", response_model=CarrierRead, status_code=status.HTTP_201_CREATED)
def create_carrier(
payload: CarrierCreate,
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 = PlCarrier(
id=generate_uuid(),
tenant_no=tenant_no,
carrier_name=payload.carrier_name,
contact_name=payload.contact_name,
contact_phone=payload.contact_phone,
status=payload.status,
remark=payload.remark,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(carrier)
db.commit()
db.refresh(carrier)
return carrier
@router.get("/carrier/{id}", response_model=CarrierRead)
def get_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)
return carrier
@router.put("/carrier/{id}", response_model=CarrierRead)
def update_carrier(
id: str,
payload: CarrierUpdate,
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)
for key, value in payload.model_dump(exclude_unset=True).items():
setattr(carrier, key, value)
carrier.update_by = user.id
db.commit()
db.refresh(carrier)
return carrier
@router.delete("/carrier/{id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_carrier(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> None:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
carrier = _get_carrier(db, tenant_no, id)
carrier.del_flag = 1
carrier.update_by = user.id
db.commit()
def _get_carrier(db: Session, tenant_no: str, carrier_id: str) -> PlCarrier:
carrier = (
db.query(PlCarrier)
.filter(
PlCarrier.id == carrier_id,
PlCarrier.tenant_no == tenant_no,
PlCarrier.del_flag == 0,
)
.first()
)
if not carrier:
raise HTTPException(status_code=404, detail="承运商不存在")
return carrier
# =============================================================================
# 车辆 API
# =============================================================================
def _vehicle_to_read(
vehicle: PlVehicle,
summary: Optional[str] = None,
default_driver_name: Optional[str] = None,
) -> VehicleRead:
data = VehicleRead.model_validate(vehicle)
if summary is not None:
data.personnel_summary = summary
if default_driver_name is not None:
data.default_driver_name = default_driver_name
return data
def _vehicle_to_detail(
db: Session, tenant_no: str, vehicle: PlVehicle
) -> VehicleDetailRead:
summaries = load_vehicle_personnel_summaries(db, tenant_no, [vehicle.id])
summary, default_name = summaries.get(vehicle.id, ("", None))
personnel_list = load_vehicle_personnel_rows(db, tenant_no, vehicle.id)
cert_list = certs_to_read(
list_owner_certs(db, tenant_no, "vehicle", vehicle.id)
)
base = _vehicle_to_read(vehicle, summary, default_name)
return VehicleDetailRead(
**base.model_dump(by_alias=False),
personnel_list=personnel_list,
cert_list=cert_list,
)
@router.get("/vehicle", response_model=list[VehicleRead])
def list_vehicles(
q: Optional[str] = Query(default=None, description="模糊搜索车牌号"),
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="车辆状态"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> list[VehicleRead]:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlVehicle).filter(
PlVehicle.tenant_no == tenant_no,
PlVehicle.del_flag == 0,
)
if vehicle_type:
query = query.filter(PlVehicle.vehicle_type == vehicle_type)
if carrier_id:
query = query.filter(PlVehicle.carrier_id == carrier_id)
if vehicle_status:
query = query.filter(PlVehicle.vehicle_status == vehicle_status)
if q:
query = query.filter(PlVehicle.license_plate.contains(q))
query = query.order_by(
case((PlVehicle.order_num.is_(None), 1), else_=0).asc(),
PlVehicle.create_time.desc(),
)
vehicles = query.all()
summaries = load_vehicle_personnel_summaries(
db, tenant_no, [v.id for v in vehicles]
)
return [
_vehicle_to_read(v, *summaries.get(v.id, ("", None)))
for v in vehicles
]
@router.post("/vehicle", response_model=VehicleDetailRead, status_code=status.HTTP_201_CREATED)
def create_vehicle(
payload: VehicleCreate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> VehicleDetailRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
existing = (
db.query(PlVehicle)
.filter(
PlVehicle.license_plate == payload.license_plate,
PlVehicle.del_flag == 0,
)
.first()
)
if existing:
raise HTTPException(status_code=400, detail="车牌号已存在")
vehicle = PlVehicle(
id=generate_uuid(),
tenant_no=tenant_no,
vehicle_type=payload.vehicle_type,
carrier_id=payload.carrier_id,
carrier_name=payload.carrier_name,
license_plate=payload.license_plate,
load_capacity=payload.load_capacity,
vehicle_status=payload.vehicle_status,
remark=payload.remark,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(vehicle)
db.flush()
try:
save_vehicle_personnel(
db,
vehicle.id,
payload.personnel_list,
tenant_no,
user_id=user.id,
dept_id=user.dept_id,
)
save_owner_certs(
db,
"vehicle",
vehicle.id,
payload.cert_list,
tenant_no,
user_id=user.id,
dept_id=user.dept_id,
)
db.commit()
except HTTPException:
db.rollback()
raise
except Exception:
db.rollback()
raise
db.refresh(vehicle)
return _vehicle_to_detail(db, tenant_no, vehicle)
@router.get("/vehicle/{id}", response_model=VehicleDetailRead)
def get_vehicle(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> VehicleDetailRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
vehicle = _get_vehicle(db, tenant_no, id)
return _vehicle_to_detail(db, tenant_no, vehicle)
@router.put("/vehicle/{id}", response_model=VehicleDetailRead)
def update_vehicle(
id: str,
payload: VehicleUpdate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> VehicleDetailRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
vehicle = _get_vehicle(db, tenant_no, id)
personnel_list = payload.personnel_list
cert_list = payload.cert_list
data = payload.model_dump(
exclude_unset=True, exclude={"personnel_list", "cert_list"}
)
for key, value in data.items():
setattr(vehicle, key, value)
vehicle.update_by = user.id
try:
if personnel_list is not None:
save_vehicle_personnel(
db,
vehicle.id,
personnel_list,
tenant_no,
user_id=user.id,
dept_id=user.dept_id,
)
if cert_list is not None:
save_owner_certs(
db,
"vehicle",
vehicle.id,
cert_list,
tenant_no,
user_id=user.id,
dept_id=user.dept_id,
)
db.commit()
except HTTPException:
db.rollback()
raise
except Exception:
db.rollback()
raise
db.refresh(vehicle)
return _vehicle_to_detail(db, tenant_no, vehicle)
@router.delete("/vehicle/{id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_vehicle(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> None:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
vehicle = _get_vehicle(db, tenant_no, id)
vehicle.del_flag = 1
vehicle.update_by = user.id
db.commit()
def _get_vehicle(db: Session, tenant_no: str, vehicle_id: str) -> PlVehicle:
vehicle = (
db.query(PlVehicle)
.filter(
PlVehicle.id == vehicle_id,
PlVehicle.tenant_no == tenant_no,
PlVehicle.del_flag == 0,
)
.first()
)
if not vehicle:
raise HTTPException(status_code=404, detail="车辆不存在")
return vehicle
# =============================================================================
# 人员 API
# =============================================================================
def _personnel_to_read(
db: Session, tenant_no: str, personnel: PlPersonnel
) -> PersonnelRead:
nearest = nearest_expire_date(db, tenant_no, "personnel", personnel.id)
data = PersonnelRead.model_validate(personnel)
data.nearest_expire_date = nearest
return data
def _personnel_to_detail(
db: Session, tenant_no: str, personnel: PlPersonnel
) -> PersonnelDetailRead:
base = _personnel_to_read(db, tenant_no, personnel)
cert_list = certs_to_read(
list_owner_certs(db, tenant_no, "personnel", personnel.id)
)
return PersonnelDetailRead(
**base.model_dump(by_alias=False),
cert_list=cert_list,
)
@router.get("/personnel", response_model=list[PersonnelRead])
def list_personnel(
q: Optional[str] = Query(default=None, description="模糊搜索姓名/手机号"),
status: Optional[str] = Query(default=None, description="状态"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> list[PersonnelRead]:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlPersonnel).filter(
PlPersonnel.tenant_no == tenant_no,
PlPersonnel.del_flag == 0,
)
if status:
query = query.filter(PlPersonnel.status == status)
if q:
query = query.filter(
or_(
func.lower(PlPersonnel.personnel_name).contains(q.lower()),
PlPersonnel.phone_no.contains(q),
)
)
query = query.order_by(
case((PlPersonnel.order_num.is_(None), 1), else_=0).asc(),
PlPersonnel.create_time.desc(),
)
rows = query.all()
return [_personnel_to_read(db, tenant_no, p) for p in rows]
@router.post("/personnel", response_model=PersonnelDetailRead, status_code=status.HTTP_201_CREATED)
def create_personnel(
payload: PersonnelCreate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PersonnelDetailRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
personnel = PlPersonnel(
id=generate_uuid(),
tenant_no=tenant_no,
personnel_name=payload.personnel_name,
phone_no=payload.phone_no,
age=payload.age,
id_card_no=payload.id_card_no,
status=payload.status,
remark=payload.remark,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(personnel)
db.flush()
try:
save_owner_certs(
db,
"personnel",
personnel.id,
payload.cert_list,
tenant_no,
user_id=user.id,
dept_id=user.dept_id,
)
db.commit()
except Exception:
db.rollback()
raise
db.refresh(personnel)
return _personnel_to_detail(db, tenant_no, personnel)
@router.get("/personnel/{id}", response_model=PersonnelDetailRead)
def get_personnel(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PersonnelDetailRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
personnel = _get_personnel(db, tenant_no, id)
return _personnel_to_detail(db, tenant_no, personnel)
@router.put("/personnel/{id}", response_model=PersonnelDetailRead)
def update_personnel(
id: str,
payload: PersonnelUpdate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PersonnelDetailRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
personnel = _get_personnel(db, tenant_no, id)
cert_list = payload.cert_list
data = payload.model_dump(exclude_unset=True, exclude={"cert_list"})
for key, value in data.items():
setattr(personnel, key, value)
personnel.update_by = user.id
try:
if cert_list is not None:
save_owner_certs(
db,
"personnel",
personnel.id,
cert_list,
tenant_no,
user_id=user.id,
dept_id=user.dept_id,
)
db.commit()
except Exception:
db.rollback()
raise
db.refresh(personnel)
return _personnel_to_detail(db, tenant_no, personnel)
@router.delete("/personnel/{id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_personnel(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> None:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
personnel = _get_personnel(db, tenant_no, id)
personnel.del_flag = 1
personnel.update_by = user.id
db.commit()
def _get_personnel(db: Session, tenant_no: str, personnel_id: str) -> PlPersonnel:
personnel = (
db.query(PlPersonnel)
.filter(
PlPersonnel.id == personnel_id,
PlPersonnel.tenant_no == tenant_no,
PlPersonnel.del_flag == 0,
)
.first()
)
if not personnel:
raise HTTPException(status_code=404, detail="人员不存在")
return personnel
# =============================================================================
# 司机 API(兼容别名,内部使用 pl_personnel)
# =============================================================================
def _personnel_to_driver_read(personnel: PlPersonnel) -> DriverRead:
return DriverRead(
id=personnel.id,
driver_name=personnel.personnel_name,
phone_no=personnel.phone_no,
id_card_no=personnel.id_card_no,
tenant_no=personnel.tenant_no,
order_num=personnel.order_num,
remark=personnel.remark,
create_by=personnel.create_by,
create_dept_id=personnel.create_dept_id,
create_time=personnel.create_time,
update_by=personnel.update_by,
update_time=personnel.update_time,
del_flag=personnel.del_flag,
)
@router.get("/driver", response_model=list[DriverRead])
def list_drivers(
q: Optional[str] = Query(default=None, description="模糊搜索姓名/手机号"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> list[DriverRead]:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlPersonnel).filter(
PlPersonnel.tenant_no == tenant_no,
PlPersonnel.del_flag == 0,
)
if q:
query = query.filter(
or_(
func.lower(PlPersonnel.personnel_name).contains(q.lower()),
PlPersonnel.phone_no.contains(q),
)
)
query = query.order_by(
case((PlPersonnel.order_num.is_(None), 1), else_=0).asc(),
PlPersonnel.create_time.desc(),
)
return [_personnel_to_driver_read(p) for p in query.all()]
@router.post("/driver", response_model=DriverRead, status_code=status.HTTP_201_CREATED)
def create_driver(
payload: DriverCreate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> DriverRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
personnel = PlPersonnel(
id=generate_uuid(),
tenant_no=tenant_no,
personnel_name=payload.driver_name,
phone_no=payload.phone_no,
id_card_no=payload.id_card_no,
status="1",
remark=payload.remark,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(personnel)
db.commit()
db.refresh(personnel)
return _personnel_to_driver_read(personnel)
@router.get("/driver/{id}", response_model=DriverRead)
def get_driver(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> DriverRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
personnel = _get_personnel(db, tenant_no, id)
return _personnel_to_driver_read(personnel)
@router.put("/driver/{id}", response_model=DriverRead)
def update_driver(
id: str,
payload: DriverUpdate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> DriverRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
personnel = _get_personnel(db, tenant_no, id)
if payload.driver_name is not None:
personnel.personnel_name = payload.driver_name
if payload.phone_no is not None:
personnel.phone_no = payload.phone_no
if payload.id_card_no is not None:
personnel.id_card_no = payload.id_card_no
if payload.remark is not None:
personnel.remark = payload.remark
personnel.update_by = user.id
db.commit()
db.refresh(personnel)
return _personnel_to_driver_read(personnel)
@router.delete("/driver/{id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_driver(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> None:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
personnel = _get_personnel(db, tenant_no, id)
personnel.del_flag = 1
personnel.update_by = user.id
db.commit()
# =============================================================================
# 车辆-司机绑定 API(兼容,写入 pl_vehicle_personnel)
# =============================================================================
@router.post("/vehicle-driver", status_code=status.HTTP_201_CREATED)
def bind_vehicle_driver(
payload: VehicleDriverCreate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> dict:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
if payload.is_default == 1:
db.query(PlVehiclePersonnel).filter(
PlVehiclePersonnel.vehicle_id == payload.vehicle_id,
PlVehiclePersonnel.role == "driver",
PlVehiclePersonnel.del_flag == 0,
).update({"is_default": 0})
vd = PlVehiclePersonnel(
id=generate_uuid(),
tenant_no=tenant_no,
vehicle_id=payload.vehicle_id,
personnel_id=payload.driver_id,
role="driver",
is_default=payload.is_default,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(vd)
db.commit()
return {"id": vd.id}
@router.delete("/vehicle-driver/{id}", status_code=status.HTTP_204_NO_CONTENT)
def unbind_vehicle_driver(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> None:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
vd = (
db.query(PlVehiclePersonnel)
.filter(
PlVehiclePersonnel.id == id,
PlVehiclePersonnel.tenant_no == tenant_no,
PlVehiclePersonnel.del_flag == 0,
)
.first()
)
if not vd:
vd = (
db.query(PlVehicleDriver)
.filter(
PlVehicleDriver.id == id,
PlVehicleDriver.tenant_no == tenant_no,
PlVehicleDriver.del_flag == 0,
)
.first()
)
if vd:
vd.del_flag = 1
db.commit()
+333
View File
@@ -0,0 +1,333 @@
"""运输计划管理 - 运费结算 API"""
from datetime import date
from typing import Optional
import json
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import func
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.tenant_context import get_tenant_no
from app.core.utils import generate_uuid
from app.models.pl_models import (
PlFreightSettlement,
PlFreightSettlementTransport,
PlRemittanceVoucher,
PlTransport,
)
from app.schemas.pl.freight import (
FreightSettlementCreate,
FreightSettlementListQuery,
FreightSettlementListResponse,
FreightSettlementRead,
FreightSettlementUpdate,
FreightSettlementWithTransports,
RemittanceVoucherCreate,
RemittanceVoucherRead,
)
router = APIRouter(prefix="/freight", tags=["运输计划-运费结算"])
def _generate_settlement_no(db: Session) -> str:
"""生成结算单编号"""
today = date.today()
prefix = f"SXJS{today.strftime('%Y%m%d')}"
last = (
db.query(PlFreightSettlement)
.filter(
PlFreightSettlement.settlement_no.like(f"{prefix}%"),
PlFreightSettlement.del_flag == 0,
)
.order_by(PlFreightSettlement.settlement_no.desc())
.first()
)
if last:
last_seq = int(last.settlement_no[-4:])
seq = last_seq + 1
else:
seq = 1
return f"{prefix}{seq:04d}"
# =============================================================================
# 结算单列表
# =============================================================================
@router.get("/", response_model=FreightSettlementListResponse)
def list_settlements(
q: Optional[str] = Query(default=None, description="模糊搜索"),
settlement_status: Optional[str] = Query(default=None, alias="settlementStatus", description="结算状态"),
page: int = Query(default=1, ge=1),
page_size: int = Query(default=20, ge=1, le=100, alias="pageSize"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> FreightSettlementListResponse:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlFreightSettlement).filter(
PlFreightSettlement.tenant_no == tenant_no,
PlFreightSettlement.del_flag == 0,
)
if settlement_status:
query = query.filter(PlFreightSettlement.settlement_status == settlement_status)
if q:
query = query.filter(PlFreightSettlement.settlement_no.contains(q))
total = query.count()
offset = (page - 1) * page_size
settlements = query.order_by(PlFreightSettlement.create_time.desc()).offset(offset).limit(page_size).all()
return FreightSettlementListResponse(total=total, list=settlements)
# =============================================================================
# 生成结算单
# =============================================================================
@router.post("/", response_model=FreightSettlementRead, status_code=status.HTTP_201_CREATED)
def create_settlement(
payload: FreightSettlementCreate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> FreightSettlementRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
# 计算总运费
transports = (
db.query(PlTransport)
.filter(
PlTransport.id.in_(payload.transport_ids),
PlTransport.tenant_no == tenant_no,
PlTransport.del_flag == 0,
)
.all()
)
if not transports:
raise HTTPException(status_code=400, detail="请选择有效的运输单")
total_freight = sum(float(t.freight_amount or 0) for t in transports)
settlement_no = _generate_settlement_no(db)
settlement = PlFreightSettlement(
id=generate_uuid(),
tenant_no=tenant_no,
settlement_no=settlement_no,
total_freight=total_freight,
settlement_status="pending",
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(settlement)
# 关联运输单
for t in transports:
st = PlFreightSettlementTransport(
id=generate_uuid(),
tenant_no=tenant_no,
settlement_id=settlement.id,
transport_id=t.id,
freight_amount=t.freight_amount,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(st)
db.commit()
db.refresh(settlement)
return settlement
# =============================================================================
# 获取结算单详情
# =============================================================================
@router.get("/{id}", response_model=FreightSettlementWithTransports)
def get_settlement(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> FreightSettlementWithTransports:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
settlement = _get_settlement(db, tenant_no, id)
# 获取关联的运输单
transport_links = (
db.query(PlFreightSettlementTransport)
.filter(
PlFreightSettlementTransport.settlement_id == id,
PlFreightSettlementTransport.del_flag == 0,
)
.all()
)
transport_ids = [t.transport_id for t in transport_links]
transports = (
db.query(PlTransport)
.filter(PlTransport.id.in_(transport_ids), PlTransport.del_flag == 0)
.all()
)
result = FreightSettlementWithTransports.model_validate(settlement)
result.transports = transports
return result
# =============================================================================
# 更新结算单
# =============================================================================
@router.put("/{id}", response_model=FreightSettlementRead)
def update_settlement(
id: str,
payload: FreightSettlementUpdate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> FreightSettlementRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
settlement = _get_settlement(db, tenant_no, id)
update_data = payload.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(settlement, key, value)
settlement.update_by = user.id
db.commit()
db.refresh(settlement)
return settlement
# =============================================================================
# 提交结算单
# =============================================================================
@router.post("/{id}/submit", response_model=FreightSettlementRead)
def submit_settlement(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> FreightSettlementRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
settlement = _get_settlement(db, tenant_no, id)
if settlement.settlement_status != "pending":
raise HTTPException(status_code=400, detail="当前状态不允许提交")
settlement.settlement_status = "submitted"
settlement.update_by = user.id
db.commit()
db.refresh(settlement)
return settlement
# =============================================================================
# 审核结算单
# =============================================================================
@router.post("/{id}/approve", response_model=FreightSettlementRead)
def approve_settlement(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> FreightSettlementRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
settlement = _get_settlement(db, tenant_no, id)
if settlement.settlement_status not in ("submitted",):
raise HTTPException(status_code=400, detail="当前状态不允许审核")
settlement.settlement_status = "confirmed"
settlement.update_by = user.id
db.commit()
db.refresh(settlement)
return settlement
# =============================================================================
# 汇款凭证
# =============================================================================
@router.post("/voucher", status_code=status.HTTP_201_CREATED)
def create_voucher(
payload: RemittanceVoucherCreate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> RemittanceVoucherRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
voucher = PlRemittanceVoucher(
id=generate_uuid(),
tenant_no=tenant_no,
settlement_id=payload.settlement_id,
remittance_date=payload.remittance_date,
remittance_amount=payload.remittance_amount,
voucher_urls=json.dumps(payload.voucher_urls) if payload.voucher_urls else None,
remark=payload.remark,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(voucher)
db.commit()
db.refresh(voucher)
result = RemittanceVoucherRead.model_validate(voucher)
if voucher.voucher_urls:
result.voucher_urls = voucher.voucher_urls
return result
@router.get("/voucher/{settlement_id}", response_model=list[RemittanceVoucherRead])
def list_vouchers(
settlement_id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> list[RemittanceVoucherRead]:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
vouchers = (
db.query(PlRemittanceVoucher)
.filter(
PlRemittanceVoucher.settlement_id == settlement_id,
PlRemittanceVoucher.tenant_no == tenant_no,
PlRemittanceVoucher.del_flag == 0,
)
.order_by(PlRemittanceVoucher.create_time.desc())
.all()
)
return vouchers
# =============================================================================
# 辅助函数
# =============================================================================
def _get_settlement(db: Session, tenant_no: str, settlement_id: str) -> PlFreightSettlement:
settlement = (
db.query(PlFreightSettlement)
.filter(
PlFreightSettlement.id == settlement_id,
PlFreightSettlement.tenant_no == tenant_no,
PlFreightSettlement.del_flag == 0,
)
.first()
)
if not settlement:
raise HTTPException(status_code=404, detail="结算单不存在")
return settlement
+342
View File
@@ -0,0 +1,342 @@
"""运输计划管理 - 盘存统计 API"""
from datetime import date
from decimal import Decimal
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import func
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.tenant_context import get_tenant_no
from app.core.utils import generate_uuid
from app.models.pl_models import (
PlDocumentReminder,
PlInventory,
PlInventoryTransaction,
PlInventoryWarning,
)
from app.schemas.pl.inventory import (
DocumentReminderRead,
DocumentReminderUpdate,
InventoryLedgerQuery,
InventoryLedgerResponse,
InventoryRead,
InventorySummaryItem,
InventorySummaryResponse,
InventoryTransactionQuery,
InventoryTransactionRead,
InventoryTransactionResponse,
InventoryWarningRead,
InventoryWarningThreshold,
InventoryWarningUpdate,
TransportStatsItem,
TransportStatsResponse,
)
from app.services.pl_cert_service import scan_cert_expiry
router = APIRouter(prefix="/inventory", tags=["运输计划-盘存统计"])
# =============================================================================
# 库存台账
# =============================================================================
@router.get("/ledger", response_model=InventoryLedgerResponse)
def get_inventory_ledger(
product_name: Optional[str] = Query(default=None, alias="productName", description="产品名称"),
page: int = Query(default=1, ge=1),
page_size: int = Query(default=20, ge=1, le=100, alias="pageSize"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> InventoryLedgerResponse:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlInventory).filter(
PlInventory.tenant_no == tenant_no,
PlInventory.del_flag == 0,
)
if product_name:
query = query.filter(PlInventory.product_name.contains(product_name))
total = query.count()
offset = (page - 1) * page_size
items = query.order_by(PlInventory.product_name).offset(offset).limit(page_size).all()
return InventoryLedgerResponse(total=total, list=items)
# =============================================================================
# 库存预警阈值设置
# =============================================================================
@router.post("/warning-threshold")
def set_warning_threshold(
payload: InventoryWarningThreshold,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> dict:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
inventory = (
db.query(PlInventory)
.filter(
PlInventory.product_id == payload.product_id,
PlInventory.tenant_no == tenant_no,
PlInventory.del_flag == 0,
)
.first()
)
if inventory:
inventory.low_stock_warning = payload.low_stock_warning
inventory.high_stock_warning = payload.high_stock_warning
else:
# 创建库存记录
inventory = PlInventory(
id=generate_uuid(),
tenant_no=tenant_no,
product_id=payload.product_id,
product_no="",
product_name="",
unit="吨",
stock_qty=0,
stock_amount=0,
low_stock_warning=payload.low_stock_warning,
high_stock_warning=payload.high_stock_warning,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(inventory)
db.commit()
return {"success": True}
# =============================================================================
# 库存预警列表
# =============================================================================
@router.get("/warnings", response_model=list[InventoryWarningRead])
def list_warnings(
status: Optional[str] = Query(default=None, description="状态"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> list[InventoryWarningRead]:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlInventoryWarning).filter(
PlInventoryWarning.tenant_no == tenant_no,
PlInventoryWarning.del_flag == 0,
)
if status:
query = query.filter(PlInventoryWarning.status == status)
return query.order_by(PlInventoryWarning.create_time.desc()).all()
@router.put("/warnings/{id}", response_model=InventoryWarningRead)
def update_warning(
id: str,
payload: InventoryWarningUpdate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> InventoryWarningRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
warning = (
db.query(PlInventoryWarning)
.filter(
PlInventoryWarning.id == id,
PlInventoryWarning.tenant_no == tenant_no,
PlInventoryWarning.del_flag == 0,
)
.first()
)
if not warning:
raise HTTPException(status_code=404, detail="预警不存在")
if payload.status == "resolved":
warning.status = "resolved"
from datetime import datetime
warning.resolve_time = datetime.now()
warning.resolve_remark = payload.resolve_remark
db.commit()
db.refresh(warning)
return warning
# =============================================================================
# 出入库明细
# =============================================================================
@router.get("/transactions", response_model=InventoryTransactionResponse)
def list_transactions(
product_id: Optional[str] = Query(default=None, alias="productId", description="产品ID"),
transaction_type: Optional[str] = Query(default=None, alias="transactionType", description="事务类型"),
date_from: Optional[date] = Query(default=None, alias="dateFrom", description="开始日期"),
date_to: Optional[date] = Query(default=None, alias="dateTo", description="结束日期"),
page: int = Query(default=1, ge=1),
page_size: int = Query(default=20, ge=1, le=100, alias="pageSize"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> InventoryTransactionResponse:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlInventoryTransaction).filter(
PlInventoryTransaction.tenant_no == tenant_no,
PlInventoryTransaction.del_flag == 0,
)
if product_id:
query = query.filter(PlInventoryTransaction.product_id == product_id)
if transaction_type:
query = query.filter(PlInventoryTransaction.transaction_type == transaction_type)
if date_from:
query = query.filter(PlInventoryTransaction.create_time >= date_from)
if date_to:
query = query.filter(PlInventoryTransaction.create_time <= date_to)
total = query.count()
offset = (page - 1) * page_size
items = query.order_by(PlInventoryTransaction.create_time.desc()).offset(offset).limit(page_size).all()
return InventoryTransactionResponse(total=total, list=items)
# =============================================================================
# 出入库汇总
# =============================================================================
@router.get("/summary", response_model=InventorySummaryResponse)
def get_summary(
group_by: str = Query(default="month", description="汇总维度 month/week"),
date_from: date = Query(..., alias="dateFrom", description="开始日期"),
date_to: date = Query(..., alias="dateTo", description="结束日期"),
product_id: Optional[str] = Query(default=None, alias="productId", description="产品ID"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> InventorySummaryResponse:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlInventoryTransaction).filter(
PlInventoryTransaction.tenant_no == tenant_no,
PlInventoryTransaction.del_flag == 0,
PlInventoryTransaction.create_time >= date_from,
PlInventoryTransaction.create_time <= date_to,
)
if product_id:
query = query.filter(PlInventoryTransaction.product_id == product_id)
transactions = query.all()
# 按产品分组汇总
summary_map = {}
for t in transactions:
key = t.product_id
if key not in summary_map:
summary_map[key] = {
"product_id": t.product_id,
"product_name": t.product_name,
"inbound_qty": Decimal("0"),
"outbound_qty": Decimal("0"),
}
if t.transaction_type == "inbound":
summary_map[key]["inbound_qty"] += t.qty
else:
summary_map[key]["outbound_qty"] += abs(t.qty)
items = []
for key, data in summary_map.items():
net = data["inbound_qty"] - data["outbound_qty"]
items.append(InventorySummaryItem(
period="汇总",
product_id=data["product_id"],
product_name=data["product_name"],
inbound_qty=data["inbound_qty"],
outbound_qty=data["outbound_qty"],
net_change=net,
))
return InventorySummaryResponse(list=items)
# =============================================================================
# 证件到期提醒
# =============================================================================
@router.get("/document-reminders", response_model=list[DocumentReminderRead])
def list_document_reminders(
status: Optional[str] = Query(default=None, description="状态"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> list[DocumentReminderRead]:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlDocumentReminder).filter(
PlDocumentReminder.tenant_no == tenant_no,
PlDocumentReminder.del_flag == 0,
)
if status:
query = query.filter(PlDocumentReminder.status == status)
return query.order_by(PlDocumentReminder.expire_date.asc()).all()
@router.put("/document-reminders/{id}", response_model=DocumentReminderRead)
def update_document_reminder(
id: str,
payload: DocumentReminderUpdate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> DocumentReminderRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
reminder = (
db.query(PlDocumentReminder)
.filter(
PlDocumentReminder.id == id,
PlDocumentReminder.tenant_no == tenant_no,
PlDocumentReminder.del_flag == 0,
)
.first()
)
if not reminder:
raise HTTPException(status_code=404, detail="提醒不存在")
reminder.status = payload.status
if payload.remark:
reminder.remark = payload.remark
db.commit()
db.refresh(reminder)
return reminder
# =============================================================================
# 生成证件到期提醒(定时任务调用)
# =============================================================================
@router.post("/check-document-expiry")
def check_document_expiry(db: Session = Depends(get_db)) -> dict:
"""检查证件到期,生成提醒(供定时任务调用)"""
created_count = scan_cert_expiry(db)
db.commit()
return {"created_count": created_count}
+927
View File
@@ -0,0 +1,927 @@
"""运输计划管理 - 计划 API"""
from datetime import date
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import func, or_
from sqlalchemy.orm import Session
from app.core.config import settings
from app.core.database import get_db
from app.core.db_auth import DbUserContext, get_db_current_user
from app.core.tenant_context import get_tenant_no
from app.core.utils import generate_uuid
from app.models.crm_models import CrmContract, CrmContractProduct, CrmProduct
from app.models.db_models import DbInboundOutbound
from app.models.pl_models import (
PlCarrier,
PlDriver,
PlPlan,
PlPlanProduct,
PlPlanTransport,
PlTransport,
PlTransportDbLink,
PlVehicle,
)
from app.schemas.pl import PlanProductCreate
from app.schemas.pl.plan import (
CreateFromContractRequest,
PlanCreate,
PlanCreateFull,
PlanListQuery,
PlanListResponse,
PlanProductCertsUpdate,
PlanProductRead,
PlanRead,
PlanUpdate,
PlanWithProducts,
)
from app.schemas.pl.transport import PlanArrangeInfoRead, TransportInventoryLinkRead
from app.services.pl_dibang_bridge_service import revoke_regeneratable_dibang_for_transport
from app.services.pl_plan_service import (
apply_vehicle_prefill_to_plan,
build_plan_product,
calc_plan_total_amount,
clear_draft_transport_for_plan,
determine_plan_type,
resolve_hazard_flags_from_crm,
sync_transport_prefill_for_plan,
update_plan_product_certs,
validate_create_full,
)
router = APIRouter(prefix="/plan", tags=["运输计划-计划管理"])
def _generate_plan_no(db: Session) -> str:
"""生成计划编号 SXDDHYYYYMMDD######"""
today = date.today()
prefix = f"SXDDH{today.strftime('%Y%m%d')}"
# uk_plan_no 对全表生效(含软删),取号时不能过滤 del_flag
last_plan = (
db.query(PlPlan)
.filter(PlPlan.plan_no.like(f"{prefix}%"))
.order_by(PlPlan.plan_no.desc())
.first()
)
if last_plan:
last_seq = int(last_plan.plan_no[-6:])
seq = last_seq + 1
else:
seq = 1
return f"{prefix}{seq:06d}"
def _determine_plan_type(supplier_name: Optional[str], destination_name: Optional[str]) -> str:
"""根据供应商和目的地自动判断单据类型"""
return determine_plan_type(supplier_name, destination_name)
def _get_plan_type_label(plan_type: str) -> str:
labels = {
"direct": "直销单",
"inbound": "入库单",
"outbound": "出库单",
}
return labels.get(plan_type, plan_type)
def _generate_notify_message(plan: PlPlan, products: list) -> str:
"""生成通知信息"""
product_names = "、".join([p.product_name for p in products[:3]])
if len(products) > 3:
product_names += "等"
return f"""计划号:{plan.plan_no}
企业名称:{plan.customer_name or ''}
提货单位:{plan.destination_name or ''}
到货时间:{plan.contract_end_date or ''}
药品名称:{product_names}
到货吨位:{sum(float(p.inbound_estimate_qty or p.outbound_estimate_qty or 0) for p in products)}吨
备注:"""
# =============================================================================
# 计划列表
# =============================================================================
@router.get("/", response_model=PlanListResponse)
def list_plans(
q: Optional[str] = Query(default=None, description="模糊搜索"),
plan_no: Optional[str] = Query(default=None, description="计划编号"),
plan_type: Optional[str] = Query(default=None, alias="planType", description="单据类型"),
follow_status: Optional[str] = Query(default=None, alias="followStatus", description="跟进状态"),
transport_status: Optional[str] = Query(default=None, alias="transportStatus", description="运输状态"),
archive_status: Optional[str] = Query(default=None, alias="archiveStatus", description="归档状态"),
customer_name: Optional[str] = Query(default=None, alias="customerName", description="客户名称"),
plan_date_from: Optional[date] = Query(default=None, alias="planDateFrom", description="计划日期开始"),
plan_date_to: Optional[date] = Query(default=None, alias="planDateTo", description="计划日期结束"),
page: int = Query(default=1, ge=1),
page_size: int = Query(default=20, ge=1, le=100, alias="pageSize"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanListResponse:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlPlan).filter(
PlPlan.tenant_no == tenant_no,
PlPlan.del_flag == 0,
)
if q:
query = query.filter(
or_(
PlPlan.plan_no.contains(q),
func.lower(PlPlan.customer_name).contains(q.lower()),
)
)
if plan_no:
query = query.filter(PlPlan.plan_no.contains(plan_no))
if plan_type:
query = query.filter(PlPlan.plan_type == plan_type)
if follow_status:
query = query.filter(PlPlan.follow_status == follow_status)
if transport_status:
query = query.filter(PlPlan.transport_status == transport_status)
if archive_status:
query = query.filter(PlPlan.archive_status == archive_status)
if customer_name:
query = query.filter(func.lower(PlPlan.customer_name).contains(customer_name.lower()))
if plan_date_from:
query = query.filter(PlPlan.plan_date >= plan_date_from)
if plan_date_to:
query = query.filter(PlPlan.plan_date <= plan_date_to)
# 统计总数
total = query.count()
# 分页
offset = (page - 1) * page_size
plans = query.order_by(PlPlan.create_time.desc()).offset(offset).limit(page_size).all()
plan_ids = [plan.id for plan in plans]
products_by_plan: dict[str, list[PlPlanProduct]] = {}
if plan_ids:
all_products = (
db.query(PlPlanProduct)
.filter(
PlPlanProduct.plan_id.in_(plan_ids),
PlPlanProduct.del_flag == 0,
)
.order_by(PlPlanProduct.order_num)
.all()
)
for product in all_products:
products_by_plan.setdefault(product.plan_id, []).append(product)
result_list: list[PlanWithProducts] = []
for plan in plans:
enriched_products: list[PlanProductRead] = []
for product in products_by_plan.get(plan.id, []):
is_toxic, is_explosive = resolve_hazard_flags_from_crm(
db,
tenant_no,
product.product_id,
product.is_toxic,
product.is_explosive,
)
item = PlanProductRead.model_validate(product)
if is_toxic != int(product.is_toxic or 0) or is_explosive != int(product.is_explosive or 0):
item = item.model_copy(update={"is_toxic": is_toxic, "is_explosive": is_explosive})
enriched_products.append(item)
plan_item = PlanWithProducts.model_validate(plan)
plan_item.products = enriched_products
result_list.append(plan_item)
return PlanListResponse(total=total, list=result_list)
@router.get("/count-by-contract")
def count_plans_by_contract(
contract_ids: str = Query(..., alias="contractIds", description="合同ID,逗号分隔"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> dict:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
ids = [item.strip() for item in contract_ids.split(",") if item.strip()]
if not ids:
return {"counts": {}}
rows = (
db.query(PlPlan.contract_id, func.count(PlPlan.id))
.filter(
PlPlan.tenant_no == tenant_no,
PlPlan.del_flag == 0,
PlPlan.contract_id.in_(ids),
)
.group_by(PlPlan.contract_id)
.all()
)
return {"counts": {contract_id: count for contract_id, count in rows}}
# =============================================================================
# 创建计划
# =============================================================================
@router.post("/", response_model=PlanRead, status_code=status.HTTP_201_CREATED)
def create_plan(
payload: PlanCreate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
# 生成计划编号
plan_no = _generate_plan_no(db)
# 自动判断单据类型
plan_type = payload.plan_type
if not plan_type:
plan_type = _determine_plan_type(payload.supplier_name, payload.destination_name)
plan = PlPlan(
id=generate_uuid(),
tenant_no=tenant_no,
plan_no=plan_no,
plan_date=payload.plan_date,
belongs_company=payload.belongs_company,
plan_type=plan_type,
follow_status=payload.follow_status or "draft",
transport_status=payload.transport_status or "pending",
archive_status=payload.archive_status or "unarchived",
complete_status=payload.complete_status or "no",
contract_id=payload.contract_id,
contract_no=payload.contract_no,
supplier_id=payload.supplier_id,
supplier_name=payload.supplier_name,
destination_id=payload.destination_id,
destination_name=payload.destination_name,
customer_id=payload.customer_id,
customer_name=payload.customer_name,
contact_name=payload.contact_name,
contact_phone=payload.contact_phone,
party_a=payload.party_a,
party_b=payload.party_b,
contract_start_date=payload.contract_start_date,
contract_end_date=payload.contract_end_date,
delivery_method=payload.delivery_method,
settlement_method=payload.settlement_method,
has_freight=payload.has_freight,
pickup_address=payload.pickup_address,
pickup_time=payload.pickup_time,
pickup_notes=payload.pickup_notes,
destination_address=payload.destination_address,
delivery_time=payload.delivery_time,
destination_notes=payload.destination_notes,
follow_user_id=payload.follow_user_id or user.id,
follow_user_name=payload.follow_user_name or user.nick_name,
remark=payload.remark,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(plan)
# 添加产品明细
if payload.products:
for idx, prod in enumerate(payload.products):
pp = build_plan_product(
tenant_no=tenant_no,
plan_id=plan.id,
plan_type=plan_type,
prod=prod,
order_num=idx,
user_id=user.id,
dept_id=user.dept_id,
)
db.add(pp)
plan.total_amount = calc_plan_total_amount(payload.products or [])
db.commit()
db.refresh(plan)
return plan
@router.post("/create-full", response_model=PlanWithProducts, status_code=status.HTTP_201_CREATED)
def create_plan_full(
payload: PlanCreateFull,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanWithProducts:
"""创建运输计划(完整表单:合同产品 + 可选预选车辆,不自动安排运输)"""
validate_create_full(payload)
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
plan_no = _generate_plan_no(db)
plan_type = payload.plan_type or _determine_plan_type(payload.supplier_name, payload.destination_name)
has_vehicle = bool(payload.transport and payload.transport.vehicle_id)
plan = PlPlan(
id=generate_uuid(),
tenant_no=tenant_no,
plan_no=plan_no,
plan_date=payload.plan_date,
belongs_company=payload.belongs_company,
plan_type=plan_type,
follow_status="draft",
transport_status="pending",
archive_status="unarchived",
complete_status="no",
contract_id=payload.contract_id,
contract_no=payload.contract_no,
supplier_id=payload.supplier_id,
supplier_name=payload.supplier_name,
destination_id=payload.destination_id,
destination_name=payload.destination_name,
customer_id=payload.customer_id,
customer_name=payload.customer_name,
contact_name=payload.contact_name,
contact_phone=payload.contact_phone,
party_a=payload.party_a,
party_b=payload.party_b,
contract_start_date=payload.contract_start_date,
contract_end_date=payload.contract_end_date,
delivery_method=payload.delivery_method,
settlement_method=payload.settlement_method,
has_freight=payload.has_freight,
pickup_address=payload.pickup_address,
pickup_time=payload.pickup_time,
pickup_notes=payload.pickup_notes,
destination_address=payload.destination_address,
delivery_time=payload.delivery_time,
destination_notes=payload.destination_notes,
total_amount=calc_plan_total_amount(payload.products or []),
follow_user_id=payload.follow_user_id or user.id,
follow_user_name=payload.follow_user_name or user.nick_name,
remark=payload.remark,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(plan)
db.flush()
plan_products: list[PlPlanProduct] = []
for idx, prod in enumerate(payload.products or []):
is_toxic, is_explosive = resolve_hazard_flags_from_crm(
db,
tenant_no,
prod.product_id,
prod.is_toxic,
prod.is_explosive,
)
prod_payload = prod.model_copy(update={"is_toxic": is_toxic, "is_explosive": is_explosive})
pp = build_plan_product(
tenant_no=tenant_no,
plan_id=plan.id,
plan_type=plan_type,
prod=prod_payload,
order_num=idx,
user_id=user.id,
dept_id=user.dept_id,
)
db.add(pp)
plan_products.append(pp)
if has_vehicle and payload.transport:
apply_vehicle_prefill_to_plan(
db,
tenant_no=tenant_no,
plan=plan,
transport_payload=payload.transport,
products=plan_products,
user_id=user.id,
dept_id=user.dept_id,
)
db.commit()
db.refresh(plan)
result = PlanWithProducts.model_validate(plan)
result.products = plan_products
return result
# =============================================================================
# 从合同创建计划
# =============================================================================
@router.post("/create-from-contract", response_model=PlanRead, status_code=status.HTTP_201_CREATED)
def create_from_contract(
payload: CreateFromContractRequest,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanRead:
"""从 CRM 合同发起计划"""
from app.models.crm_models import CrmContract, CrmContractProduct
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
# 查询合同信息
contract = (
db.query(CrmContract)
.filter(CrmContract.id == payload.contract_id, CrmContract.del_flag == 0)
.first()
)
if not contract:
raise HTTPException(status_code=404, detail="合同不存在")
# 生成计划编号
plan_no = _generate_plan_no(db)
# 自动判断单据类型
plan_type = _determine_plan_type(contract.supplier_name, contract.customer_name)
plan = PlPlan(
id=generate_uuid(),
tenant_no=tenant_no,
plan_no=plan_no,
plan_date=payload.plan_date,
belongs_company=contract.belongs_company or "shanxia",
plan_type=plan_type,
follow_status="draft",
transport_status="pending",
archive_status="unarchived",
complete_status="no",
contract_id=contract.id,
contract_no=contract.contract_no,
supplier_id=contract.supplier_id,
supplier_name=contract.supplier_name,
destination_id=contract.customer_id,
destination_name=contract.customer_name,
customer_id=contract.customer_id,
customer_name=contract.customer_name,
contact_name=contract.contact_name,
contact_phone=contract.contact_phone,
party_a=contract.party_a_name,
party_b=contract.party_b_name,
contract_start_date=contract.start_date,
contract_end_date=contract.end_date,
delivery_method=contract.delivery_method,
settlement_method=contract.settlement_method,
has_freight=1 if contract.settlement_method and "含运" in contract.settlement_method else 0,
follow_user_id=payload.follow_user_id or user.id,
follow_user_name=payload.follow_user_name or user.nick_name,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(plan)
# 查询合同产品明细
contract_products = (
db.query(CrmContractProduct)
.filter(
CrmContractProduct.contract_id == contract.id,
CrmContractProduct.del_flag == 0,
)
.all()
)
# 添加产品明细
for idx, cp in enumerate(contract_products):
is_toxic, is_explosive = resolve_hazard_flags_from_crm(
db,
tenant_no,
cp.product_id,
0,
0,
)
pp = PlPlanProduct(
id=generate_uuid(),
tenant_no=tenant_no,
plan_id=plan.id,
product_id=cp.product_id,
product_no=cp.product_no,
product_name=cp.product_name,
model=cp.specification,
unit=cp.unit or "吨",
is_explosive=is_explosive,
is_toxic=is_toxic,
inbound_estimate_qty=cp.quantity,
outbound_estimate_qty=cp.quantity,
order_num=idx,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(pp)
db.commit()
db.refresh(plan)
return plan
# =============================================================================
# 获取计划详情
# =============================================================================
@router.get("/{id}", response_model=PlanWithProducts)
def get_plan(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanWithProducts:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
plan = _get_plan(db, tenant_no, id)
products = (
db.query(PlPlanProduct)
.filter(
PlPlanProduct.plan_id == id,
PlPlanProduct.del_flag == 0,
)
.order_by(PlPlanProduct.order_num)
.all()
)
enriched_products = []
for product in products:
is_toxic, is_explosive = resolve_hazard_flags_from_crm(
db,
tenant_no,
product.product_id,
product.is_toxic,
product.is_explosive,
)
item = PlanProductRead.model_validate(product)
if is_toxic != int(product.is_toxic or 0) or is_explosive != int(product.is_explosive or 0):
item = item.model_copy(update={"is_toxic": is_toxic, "is_explosive": is_explosive})
enriched_products.append(item)
result = PlanWithProducts.model_validate(plan)
result.products = enriched_products
return result
# =============================================================================
# 更新计划
# =============================================================================
@router.put("/{id}", response_model=PlanRead)
def update_plan(
id: str,
payload: PlanUpdate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
plan = _get_plan(db, tenant_no, id)
# 不能修改已归档的计划
if plan.archive_status == "archived":
raise HTTPException(status_code=400, detail="已归档的计划不能修改")
# 更新主表字段
update_data = payload.model_dump(exclude_unset=True, exclude={"products", "transport"})
for key, value in update_data.items():
setattr(plan, key, value)
plan_type = payload.plan_type or plan.plan_type
# 更新产品明细
if payload.products is not None:
existing_products = (
db.query(PlPlanProduct)
.filter(
PlPlanProduct.plan_id == id,
PlPlanProduct.del_flag == 0,
)
.all()
)
cert_by_product_id = {
row.product_id: (row.purchase_cert_url, row.transport_cert_url)
for row in existing_products
}
db.query(PlPlanProduct).filter(
PlPlanProduct.plan_id == id,
PlPlanProduct.del_flag == 0,
).update({"del_flag": 1})
plan_products: list[PlPlanProduct] = []
for idx, prod in enumerate(payload.products):
is_toxic, is_explosive = resolve_hazard_flags_from_crm(
db,
tenant_no,
prod.product_id,
prod.is_toxic,
prod.is_explosive,
)
purchase_cert = prod.purchase_cert_url
transport_cert = prod.transport_cert_url
if not purchase_cert or not transport_cert:
old_purchase, old_transport = cert_by_product_id.get(prod.product_id, (None, None))
purchase_cert = purchase_cert or old_purchase
transport_cert = transport_cert or old_transport
prod_payload = prod.model_copy(
update={
"is_toxic": is_toxic,
"is_explosive": is_explosive,
"purchase_cert_url": purchase_cert,
"transport_cert_url": transport_cert,
}
)
pp = build_plan_product(
tenant_no=tenant_no,
plan_id=id,
plan_type=plan_type,
prod=prod_payload,
order_num=idx,
user_id=user.id,
dept_id=user.dept_id,
)
db.add(pp)
plan_products.append(pp)
plan.total_amount = calc_plan_total_amount(payload.products)
else:
plan_products = (
db.query(PlPlanProduct)
.filter(
PlPlanProduct.plan_id == id,
PlPlanProduct.del_flag == 0,
)
.all()
)
# 同步运输预选 / 关联运输单运费
if payload.transport is not None:
if payload.transport.vehicle_id:
sync_transport_prefill_for_plan(
db,
tenant_no=tenant_no,
plan=plan,
transport_payload=payload.transport,
products=plan_products,
user_id=user.id,
dept_id=user.dept_id,
)
else:
clear_draft_transport_for_plan(
db,
tenant_no=tenant_no,
plan=plan,
user_id=user.id,
)
plan.update_by = user.id
db.commit()
db.refresh(plan)
return plan
@router.patch("/{id}/product-certs", response_model=PlanWithProducts)
def patch_plan_product_certs(
id: str,
payload: PlanProductCertsUpdate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanWithProducts:
"""更新计划危化品产品购买证/运输证(不触发安排运输)"""
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
update_plan_product_certs(
db,
tenant_no=tenant_no,
plan_id=id,
items=payload.products,
user_id=user.id,
)
plan = _get_plan(db, tenant_no, id)
products = (
db.query(PlPlanProduct)
.filter(
PlPlanProduct.plan_id == id,
PlPlanProduct.del_flag == 0,
)
.order_by(PlPlanProduct.order_num)
.all()
)
result = PlanWithProducts.model_validate(plan)
result.products = products
return result
def _build_driver_url(token: str) -> str:
origin = (settings.PUBLIC_WEB_ORIGIN or "").rstrip("/")
return f"{origin}/#/public/pl/transport/{token}"
@router.get("/{id}/arrange-info", response_model=PlanArrangeInfoRead)
def get_plan_arrange_info(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanArrangeInfoRead:
"""获取计划已安排运输后的司机链接与地磅出入库关联(供查看弹窗复制简述/二维码)。"""
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
plan = _get_plan(db, tenant_no, id)
empty = PlanArrangeInfoRead(driver_url=None, license_plate=None, inventory_records=[])
if plan.follow_status == "cancelled" or plan.transport_status != "arranged" or not plan.transport_id:
return empty
transport = (
db.query(PlTransport)
.filter(
PlTransport.id == plan.transport_id,
PlTransport.tenant_no == tenant_no,
PlTransport.del_flag == 0,
)
.first()
)
if not transport or transport.transport_status == "cancelled":
return empty
token = (transport.driver_access_token or "").strip()
driver_url = _build_driver_url(token) if token else None
links = (
db.query(PlTransportDbLink)
.filter(
PlTransportDbLink.tenant_no == tenant_no,
PlTransportDbLink.plan_id == id,
PlTransportDbLink.transport_id == transport.id,
PlTransportDbLink.del_flag == 0,
)
.all()
)
inventory_records: list[TransportInventoryLinkRead] = []
for link in links:
product = (
db.query(PlPlanProduct)
.filter(
PlPlanProduct.id == link.plan_product_id,
PlPlanProduct.del_flag == 0,
)
.first()
)
inventory = (
db.query(DbInboundOutbound)
.filter(
DbInboundOutbound.id == link.db_inventory_id,
DbInboundOutbound.tenant_no == tenant_no,
DbInboundOutbound.del_flag == 0,
)
.first()
)
inventory_records.append(
TransportInventoryLinkRead(
plan_product_id=link.plan_product_id,
product_name=(product.product_name if product else "") or "",
db_purchase_plan_id=link.db_purchase_plan_id,
db_inventory_id=link.db_inventory_id,
batch_no=(inventory.batch_no if inventory else "") or "",
plan_no=plan.plan_no or "",
)
)
return PlanArrangeInfoRead(
driver_url=driver_url,
license_plate=transport.license_plate or plan.license_plate,
inventory_records=inventory_records,
)
# =============================================================================
# 取消计划
# =============================================================================
@router.post("/{id}/cancel", response_model=PlanRead)
def cancel_plan(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanRead:
"""作废运输计划:取消跟进状态、作废关联地磅出入库单、取消运输单。"""
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
plan = _get_plan(db, tenant_no, id)
if plan.follow_status == "cancelled":
raise HTTPException(status_code=400, detail="计划已作废")
if plan.archive_status == "archived":
raise HTTPException(status_code=400, detail="已归档的计划不能作废")
if plan.transport_id:
transport = (
db.query(PlTransport)
.filter(
PlTransport.id == plan.transport_id,
PlTransport.tenant_no == tenant_no,
PlTransport.del_flag == 0,
)
.first()
)
if transport:
try:
revoke_regeneratable_dibang_for_transport(
db,
tenant_no=tenant_no,
transport_id=transport.id,
user_id=user.id,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
transport.transport_status = "cancelled"
transport.update_by = user.id
plan.follow_status = "cancelled"
plan.transport_status = "pending"
plan.update_by = user.id
db.commit()
db.refresh(plan)
return plan
# =============================================================================
# 归档计划
# =============================================================================
@router.post("/{id}/archive", response_model=PlanRead)
def archive_plan(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> PlanRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
plan = _get_plan(db, tenant_no, id)
if plan.archive_status == "archived":
raise HTTPException(status_code=400, detail="计划已归档")
plan.archive_status = "archived"
plan.complete_status = "yes"
plan.update_by = user.id
db.commit()
db.refresh(plan)
return plan
# =============================================================================
# 删除计划
# =============================================================================
@router.delete("/{id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_plan(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> None:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
plan = _get_plan(db, tenant_no, id)
plan.del_flag = 1
plan.update_by = user.id
db.query(PlPlanProduct).filter(
PlPlanProduct.plan_id == id,
PlPlanProduct.tenant_no == tenant_no,
PlPlanProduct.del_flag == 0,
).update({"del_flag": 1, "update_by": user.id}, synchronize_session=False)
db.query(PlPlanTransport).filter(
PlPlanTransport.plan_id == id,
PlPlanTransport.tenant_no == tenant_no,
PlPlanTransport.del_flag == 0,
).update({"del_flag": 1, "update_by": user.id}, synchronize_session=False)
db.commit()
# =============================================================================
# 辅助函数
# =============================================================================
def _get_plan(db: Session, tenant_no: str, plan_id: str) -> PlPlan:
plan = (
db.query(PlPlan)
.filter(
PlPlan.id == plan_id,
PlPlan.tenant_no == tenant_no,
PlPlan.del_flag == 0,
)
.first()
)
if not plan:
raise HTTPException(status_code=404, detail="计划不存在")
return plan
+219
View File
@@ -0,0 +1,219 @@
"""运输计划司机免登录公共 API"""
from __future__ import annotations
import json
import os
from datetime import date, datetime
from typing import Optional
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
from sqlalchemy.orm import Session
from app.core.storage import storage
from app.core.attachment_biz import resolve_upload_folder
from app.core.config import settings
from app.core.database import get_db
from app.core.response import error_response, success_response
from app.crud import oss as oss_svc
from app.models.pl_models import PlPlan, PlPlanProduct, PlPlanTransport, PlTransport
from app.schemas.pl.transport import PublicTransportFeedback, PublicTransportPageRead, PublicTransportPlanProductRead
from app.utils.excel_export import load_dict_label_maps
router = APIRouter(prefix="/public/pl/transport", tags=["运输计划-司机公共"])
CRM_PRODUCT_UNIT = "crm_product_unit"
def _resolve_unit_label(unit_map: dict[str, str], unit_code: Optional[str]) -> str:
code = (unit_code or "").strip()
if not code:
return "吨"
return unit_map.get(code, code)
def _get_transport_by_token(db: Session, token: str) -> PlTransport:
transport = (
db.query(PlTransport)
.filter(
PlTransport.driver_access_token == token,
PlTransport.del_flag == 0,
)
.first()
)
if not transport:
raise HTTPException(status_code=404, detail="链接无效或已失效")
return transport
def _parse_feedback_images(raw: Optional[str]) -> list[str]:
if not raw:
return []
try:
parsed = json.loads(raw)
if isinstance(parsed, list):
return [str(item) for item in parsed if item]
except (TypeError, json.JSONDecodeError):
pass
return [part.strip() for part in raw.split(",") if part.strip()]
def _format_plan_date(value) -> Optional[str]:
if value is None:
return None
if isinstance(value, datetime):
return value.strftime("%Y-%m-%d")
if isinstance(value, date):
return value.isoformat()
return str(value)
def _build_public_page(db: Session, transport: PlTransport) -> PublicTransportPageRead:
link = (
db.query(PlPlanTransport)
.filter(
PlPlanTransport.transport_id == transport.id,
PlPlanTransport.del_flag == 0,
)
.order_by(PlPlanTransport.create_time.desc())
.first()
)
plan = None
products: list[PlPlanProduct] = []
if link:
plan = (
db.query(PlPlan)
.filter(PlPlan.id == link.plan_id, PlPlan.del_flag == 0)
.first()
)
if plan:
products = (
db.query(PlPlanProduct)
.filter(PlPlanProduct.plan_id == plan.id, PlPlanProduct.del_flag == 0)
.order_by(PlPlanProduct.order_num.asc(), PlPlanProduct.create_time.asc())
.all()
)
product_reads = []
unit_map = load_dict_label_maps(
db, [CRM_PRODUCT_UNIT], tenant_no=transport.tenant_no
).get(CRM_PRODUCT_UNIT, {})
for prod in products:
product_reads.append(
PublicTransportPlanProductRead(
product_name=prod.product_name or "",
model=prod.model,
package_spec=prod.package_spec,
unit=_resolve_unit_label(unit_map, prod.unit),
quantity=prod.quantity or prod.inbound_estimate_qty or prod.outbound_estimate_qty,
)
)
return PublicTransportPageRead(
plan_no=plan.plan_no if plan else transport.transport_no,
plan_date=_format_plan_date(plan.plan_date if plan else None),
plan_type=plan.plan_type if plan else "",
pickup_address=plan.pickup_address if plan else transport.start_point,
destination_address=(
(plan.destination_address or plan.destination_name) if plan else transport.end_point
),
license_plate=transport.license_plate,
driver_name=transport.driver_name,
driver_phone=transport.driver_phone,
products=product_reads,
feedback_remark=transport.feedback_remark,
feedback_images=_parse_feedback_images(transport.feedback_images),
feedback_time=transport.feedback_time,
plan_voided=(
(plan is not None and plan.follow_status == "cancelled")
or transport.transport_status == "cancelled"
),
)
@router.get("/{token}")
def get_public_transport(token: str, db: Session = Depends(get_db)):
transport = _get_transport_by_token(db, token)
page = _build_public_page(db, transport)
return success_response(page.model_dump(by_alias=True))
@router.post("/{token}/feedback")
def save_public_feedback(
token: str,
payload: PublicTransportFeedback,
db: Session = Depends(get_db),
):
transport = _get_transport_by_token(db, token)
page = _build_public_page(db, transport)
if page.plan_voided:
return error_response(400, "运输计划已作废,无法提交回执")
if payload.feedback_images is not None:
transport.feedback_images = json.dumps(payload.feedback_images)
if payload.feedback_remark is not None:
transport.feedback_remark = payload.feedback_remark
transport.feedback_time = datetime.now()
db.commit()
return success_response({"success": True, "message": "保存成功"})
def _format_file_size(size_bytes: int) -> str:
if size_bytes < 1024:
return f"{size_bytes} B"
if size_bytes < 1024 * 1024:
return f"{size_bytes / 1024:.1f} KB"
return f"{size_bytes / (1024 * 1024):.1f} MB"
@router.post("/{token}/attachments")
async def upload_public_attachment(
token: str,
file: UploadFile = File(...),
folder: Optional[str] = Form(""),
db: Session = Depends(get_db),
):
transport = _get_transport_by_token(db, token)
page = _build_public_page(db, transport)
if page.plan_voided:
return error_response(400, "运输计划已作废,无法上传附件")
if not file or not file.filename:
return error_response(400, "请选择文件")
try:
effective_folder = resolve_upload_folder(folder=folder or "", biz_type="pl_transport_feedback")
file_content = await file.read()
full_url = storage.upload_file(file_content, file.filename, effective_folder)
base_url = settings.MINIO_BASE_URL.rstrip("/") if settings.MINIO_BASE_URL else ""
if base_url and full_url.startswith(base_url + "/"):
file_url = full_url[len(base_url) + 1 :]
else:
file_url = full_url
record = oss_svc.create_oss(
db,
tenant_no=transport.tenant_no,
url=file_url,
original_name=file.filename,
file_suffix=os.path.splitext(file.filename)[1].lstrip(".") if file.filename else "",
file_size=len(file_content),
file_type=file.content_type or "",
biz_type="pl_transport_feedback",
user_id=None,
ext1=effective_folder or None,
)
db.commit()
return success_response(
{
"id": record.id,
"fileName": record.original_name,
"fileUrl": record.url,
"fileSize": record.file_size,
"fileSizeDisplay": _format_file_size(record.file_size or 0),
"fileType": record.file_type,
}
)
except Exception as exc:
db.rollback()
return error_response(500, f"上传失败: {str(exc)}")
+734
View File
@@ -0,0 +1,734 @@
"""运输计划管理 - 运输 API"""
from datetime import date, datetime
from typing import Optional
import json
import secrets
from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import BaseModel, Field
from sqlalchemy import func, or_
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.tenant_context import get_tenant_no
from app.core.utils import generate_uuid
from app.core.config import settings
from app.models.pl_models import (
PlCarrier,
PlDriver,
PlPersonnel,
PlPlan,
PlPlanProduct,
PlPlanTransport,
PlTransport,
PlTransportApproval,
PlVehicle,
)
from app.schemas.pl.transport import (
ApprovalRecordRead,
ApprovalRequest,
ApprovalSubmit,
TransportArrange,
TransportArrangeResult,
TransportCreate,
TransportFeedback,
TransportInventoryLinkRead,
TransportListQuery,
TransportListResponse,
TransportRead,
)
from app.services.pl_dibang_bridge_service import sync_dibang_for_transport
router = APIRouter(prefix="/order", tags=["运输计划-运输管理"])
def _generate_transport_no(db: Session) -> str:
"""生成运输编号 SXYS######"""
now = date.today()
prefix = f"SXYS{now.strftime('%Y%m')}"
last = (
db.query(PlTransport)
.filter(
PlTransport.transport_no.like(f"{prefix}%"),
PlTransport.del_flag == 0,
)
.order_by(PlTransport.transport_no.desc())
.first()
)
if last:
last_seq = int(last.transport_no[-6:])
seq = last_seq + 1
else:
seq = 1
return f"{prefix}{seq:06d}"
def _resolve_driver_info(db: Session, tenant_no: str, driver_id: str) -> Optional[dict]:
"""解析司机信息:优先 pl_personnel,兼容旧 pl_driver。"""
personnel = (
db.query(PlPersonnel)
.filter(
PlPersonnel.id == driver_id,
PlPersonnel.tenant_no == tenant_no,
PlPersonnel.del_flag == 0,
)
.first()
)
if personnel:
return {
"id": personnel.id,
"name": personnel.personnel_name,
"phone": personnel.phone_no,
}
legacy = (
db.query(PlDriver)
.filter(
PlDriver.id == driver_id,
PlDriver.tenant_no == tenant_no,
PlDriver.del_flag == 0,
)
.first()
)
if legacy:
return {
"id": legacy.id,
"name": legacy.driver_name,
"phone": legacy.phone_no,
}
return None
def _get_vehicle_info(db: Session, vehicle_id: str, tenant_no: Optional[str] = None) -> dict:
vehicle = db.query(PlVehicle).filter(PlVehicle.id == vehicle_id).first()
if not vehicle:
return {}
info = {
"license_plate": vehicle.license_plate,
"carrier_id": vehicle.carrier_id,
"carrier_name": vehicle.carrier_name,
}
if vehicle.default_driver_id:
driver_info = (
_resolve_driver_info(db, tenant_no, vehicle.default_driver_id)
if tenant_no
else None
)
if not driver_info:
personnel = db.query(PlPersonnel).filter(
PlPersonnel.id == vehicle.default_driver_id,
PlPersonnel.del_flag == 0,
).first()
if personnel:
driver_info = {
"id": personnel.id,
"name": personnel.personnel_name,
"phone": personnel.phone_no,
}
else:
legacy = db.query(PlDriver).filter(
PlDriver.id == vehicle.default_driver_id,
PlDriver.del_flag == 0,
).first()
if legacy:
driver_info = {
"id": legacy.id,
"name": legacy.driver_name,
"phone": legacy.phone_no,
}
if driver_info:
info["driver_id"] = driver_info["id"]
info["driver_name"] = driver_info["name"]
info["driver_phone"] = driver_info["phone"]
elif vehicle.default_driver_name:
info["driver_id"] = vehicle.default_driver_id
info["driver_name"] = vehicle.default_driver_name
return info
def _ensure_driver_access_token(transport: PlTransport) -> str:
token = (transport.driver_access_token or "").strip()
if not token:
token = secrets.token_urlsafe(32)[:64]
transport.driver_access_token = token
return token
def _build_driver_url(token: str) -> str:
origin = (settings.PUBLIC_WEB_ORIGIN or "").rstrip("/")
return f"{origin}/#/public/pl/transport/{token}"
def _build_arrange_result(
transport: PlTransport,
inventory_records: list[TransportInventoryLinkRead],
) -> TransportArrangeResult:
token = transport.driver_access_token or ""
result = TransportArrangeResult.model_validate(transport)
result.driver_access_token = token
result.driver_url = _build_driver_url(token) if token else None
result.inventory_records = inventory_records
return result
# =============================================================================
# 运输列表
# =============================================================================
@router.get("/", response_model=TransportListResponse)
def list_transports(
q: Optional[str] = Query(default=None, description="模糊搜索"),
transport_no: Optional[str] = Query(default=None, alias="transportNo", description="运输编号"),
transport_status: Optional[str] = Query(default=None, alias="transportStatus", description="运输状态"),
approval_status: Optional[str] = Query(default=None, alias="approvalStatus", description="审批状态"),
vehicle_id: Optional[str] = Query(default=None, alias="vehicleId", description="车辆ID"),
driver_id: Optional[str] = Query(default=None, alias="driverId", description="司机ID"),
page: int = Query(default=1, ge=1),
page_size: int = Query(default=20, ge=1, le=100, alias="pageSize"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> TransportListResponse:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
query = db.query(PlTransport).filter(
PlTransport.tenant_no == tenant_no,
PlTransport.del_flag == 0,
)
if q:
query = query.filter(
or_(
PlTransport.transport_no.contains(q),
PlTransport.license_plate.contains(q),
PlTransport.driver_name.contains(q),
)
)
if transport_no:
query = query.filter(PlTransport.transport_no.contains(transport_no))
if transport_status:
query = query.filter(PlTransport.transport_status == transport_status)
if approval_status:
query = query.filter(PlTransport.approval_status == approval_status)
if vehicle_id:
query = query.filter(PlTransport.vehicle_id == vehicle_id)
if driver_id:
query = query.filter(PlTransport.driver_id == driver_id)
total = query.count()
offset = (page - 1) * page_size
transports = query.order_by(PlTransport.create_time.desc()).offset(offset).limit(page_size).all()
return TransportListResponse(total=total, list=transports)
# =============================================================================
# 创建运输
# =============================================================================
@router.post("/", response_model=TransportRead, status_code=status.HTTP_201_CREATED)
def create_transport(
payload: TransportCreate,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> TransportRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
transport_no = _generate_transport_no(db)
transport = PlTransport(
id=generate_uuid(),
tenant_no=tenant_no,
transport_no=transport_no,
vehicle_id=payload.vehicle_id,
license_plate=payload.license_plate,
driver_id=payload.driver_id,
driver_name=payload.driver_name,
driver_phone=payload.driver_phone,
carrier_id=payload.carrier_id,
carrier_name=payload.carrier_name,
transport_medium=payload.transport_medium,
start_point=payload.start_point,
end_point=payload.end_point,
distance_km=payload.distance_km,
unit=payload.unit,
freight_price=payload.freight_price,
freight_amount=payload.freight_amount,
freight_type=payload.freight_type,
has_invoice=payload.has_invoice,
qr_expire_date=payload.qr_expire_date,
transport_status=payload.transport_status or "draft",
approval_status=payload.approval_status or "none",
remark=payload.remark,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(transport)
# 关联计划
if payload.plan_ids:
for pid in payload.plan_ids:
pt = PlPlanTransport(
id=generate_uuid(),
tenant_no=tenant_no,
plan_id=pid,
transport_id=transport.id,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(pt)
# 更新计划关联的运输信息
plan = db.query(PlPlan).filter(PlPlan.id == pid, PlPlan.del_flag == 0).first()
if plan:
plan.transport_id = transport.id
plan.transport_no = transport_no
plan.vehicle_id = transport.vehicle_id
plan.license_plate = transport.license_plate
plan.driver_id = transport.driver_id
plan.driver_name = transport.driver_name
db.commit()
db.refresh(transport)
return transport
# =============================================================================
# 运输安排
# =============================================================================
@router.post("/arrange/{plan_id}", response_model=TransportArrangeResult, status_code=status.HTTP_201_CREATED)
def arrange_transport(
plan_id: str,
payload: TransportArrange,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> TransportArrangeResult:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
# 获取计划
plan = db.query(PlPlan).filter(
PlPlan.id == plan_id,
PlPlan.tenant_no == tenant_no,
PlPlan.del_flag == 0,
).first()
if not plan:
raise HTTPException(status_code=404, detail="计划不存在")
# 获取车辆信息
vehicle_info = _get_vehicle_info(db, payload.vehicle_id, tenant_no)
# 获取司机信息(driverId 为人员 pl_personnel.id)
driver_info = _resolve_driver_info(db, tenant_no, payload.driver_id)
if not driver_info:
raise HTTPException(status_code=400, detail="司机不存在")
# 检查产品属性(易制毒/易制爆需要证件)
products = db.query(PlPlanProduct).filter(
PlPlanProduct.plan_id == plan_id,
PlPlanProduct.del_flag == 0,
).all()
for prod in products:
if prod.is_explosive or prod.is_toxic:
if not prod.purchase_cert_url or not prod.transport_cert_url:
raise HTTPException(
status_code=400,
detail=f"产品【{prod.product_name}】为{'易制爆' if prod.is_explosive else '易制毒'},必须上传购买证和运输证"
)
# 计算运费
freight_amount = payload.freight_amount
if payload.freight_type == "by_weight" and payload.freight_price:
total_qty = sum(
float(p.quantity or p.inbound_estimate_qty or p.outbound_estimate_qty or 0)
for p in products
)
freight_amount = total_qty * float(payload.freight_price)
carrier_name = vehicle_info.get("carrier_name")
if payload.carrier_id:
carrier = db.query(PlCarrier).filter(PlCarrier.id == payload.carrier_id).first()
if carrier:
carrier_name = carrier.carrier_name
existing_transport = None
if plan.transport_id:
existing_transport = db.query(PlTransport).filter(
PlTransport.id == plan.transport_id,
PlTransport.tenant_no == tenant_no,
PlTransport.del_flag == 0,
).first()
if existing_transport and existing_transport.transport_status == "draft":
transport = existing_transport
transport.vehicle_id = payload.vehicle_id
transport.license_plate = vehicle_info.get("license_plate")
transport.driver_id = driver_info["id"]
transport.driver_name = driver_info["name"]
transport.driver_phone = driver_info["phone"]
transport.carrier_id = payload.carrier_id or vehicle_info.get("carrier_id")
transport.carrier_name = carrier_name
transport.transport_medium = payload.transport_medium
transport.start_point = payload.start_point or plan.pickup_address
transport.end_point = payload.end_point or plan.destination_address or plan.destination_name
transport.distance_km = payload.distance_km
transport.unit = payload.unit or ("吨" if payload.freight_type == "by_weight" else "趟")
transport.freight_price = payload.freight_price
transport.freight_amount = freight_amount or 0
transport.freight_type = payload.freight_type
transport.has_invoice = payload.has_invoice
if payload.remark is not None:
transport.remark = payload.remark
transport.update_by = user.id
transport_no = transport.transport_no
else:
transport_no = _generate_transport_no(db)
transport = PlTransport(
id=generate_uuid(),
tenant_no=tenant_no,
transport_no=transport_no,
vehicle_id=payload.vehicle_id,
license_plate=vehicle_info.get("license_plate"),
driver_id=driver_info["id"],
driver_name=driver_info["name"],
driver_phone=driver_info["phone"],
carrier_id=payload.carrier_id or vehicle_info.get("carrier_id"),
carrier_name=carrier_name,
transport_medium=payload.transport_medium,
start_point=payload.start_point or plan.pickup_address,
end_point=payload.end_point or plan.destination_address or plan.destination_name,
distance_km=payload.distance_km,
unit=payload.unit or ("吨" if payload.freight_type == "by_weight" else "趟"),
freight_price=payload.freight_price,
freight_amount=freight_amount or 0,
freight_type=payload.freight_type,
has_invoice=payload.has_invoice,
qr_expire_date=payload.qr_expire_date,
transport_status="draft",
approval_status="none",
remark=payload.remark,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(transport)
pt = PlPlanTransport(
id=generate_uuid(),
tenant_no=tenant_no,
plan_id=plan_id,
transport_id=transport.id,
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(pt)
# 更新计划
plan.transport_id = transport.id
plan.transport_no = transport_no
plan.vehicle_id = transport.vehicle_id
plan.license_plate = transport.license_plate
plan.driver_id = transport.driver_id
plan.driver_name = transport.driver_name
plan.transport_status = "arranged"
plan.freight_amount = freight_amount or 0
_ensure_driver_access_token(transport)
inventory_records: list[TransportInventoryLinkRead] = []
if payload.generate_dibang_plan:
if plan.plan_type not in ("inbound", "outbound"):
raise HTTPException(status_code=400, detail="直销单不支持生成地磅计划")
try:
link_results = sync_dibang_for_transport(
db,
tenant_no=tenant_no,
plan=plan,
products=products,
transport=transport,
user_id=user.id,
dept_id=user.dept_id,
)
inventory_records = [
TransportInventoryLinkRead(
plan_product_id=item.plan_product_id,
product_name=item.product_name,
db_purchase_plan_id=item.db_purchase_plan_id,
db_inventory_id=item.db_inventory_id,
batch_no=item.batch_no,
plan_no=item.plan_no,
)
for item in link_results
]
except ValueError as exc:
db.rollback()
raise HTTPException(status_code=400, detail=str(exc)) from exc
db.commit()
db.refresh(transport)
return _build_arrange_result(transport, inventory_records)
# =============================================================================
# 获取运输详情
# =============================================================================
@router.get("/{id}", response_model=TransportRead)
def get_transport(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> TransportRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
transport = _get_transport(db, tenant_no, id)
return transport
# =============================================================================
# 生成二维码
# =============================================================================
class QrCodeResponse(BaseModel):
transport_id: str = Field(alias="transportId")
transport_no: str = Field(alias="transportNo")
qr_code: str = Field(alias="qrCode")
expire_date: Optional[date] = Field(default=None, alias="expireDate")
model_config = {"from_attributes": True, "populate_by_name": True}
@router.get("/{id}/qrcode", response_model=QrCodeResponse)
def generate_qrcode(
id: str,
expire_days: int = Query(default=30, ge=1, le=365, description="有效期天数"),
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> QrCodeResponse:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
transport = _get_transport(db, tenant_no, id)
from datetime import timedelta
expire_date = date.today() + timedelta(days=expire_days)
# 生成二维码内容(URL scheme)
qr_content = f"/transport/scan/{transport.id}?code={transport.transport_no}"
transport.qr_code = qr_content
transport.qr_expire_date = expire_date
db.commit()
return QrCodeResponse(
transport_id=transport.id,
transport_no=transport.transport_no,
qr_code=qr_content,
expire_date=expire_date,
)
# =============================================================================
# 司机扫码回传(无需登录)
# =============================================================================
@router.post("/scan/feedback")
def transport_scan_feedback(
payload: TransportFeedback,
db: Session = Depends(get_db),
) -> dict:
"""司机扫码回传,无需登录"""
transport = (
db.query(PlTransport)
.filter(
PlTransport.transport_no == payload.transport_no,
PlTransport.del_flag == 0,
)
.first()
)
if not transport:
raise HTTPException(status_code=404, detail="运输单不存在")
if payload.verify_code and payload.verify_code != transport.transport_no:
raise HTTPException(status_code=400, detail="验证码错误")
# 更新回传信息
if payload.feedback_qty:
transport.feedback_qty = payload.feedback_qty
if payload.feedback_images:
transport.feedback_images = json.dumps(payload.feedback_images)
if payload.feedback_remark:
transport.feedback_remark = payload.feedback_remark
transport.feedback_time = datetime.now()
db.commit()
return {"success": True, "message": "回传成功"}
# =============================================================================
# 提交审批
# =============================================================================
@router.post("/{id}/submit-approval", response_model=TransportRead)
def submit_approval(
id: str,
payload: ApprovalSubmit,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> TransportRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
transport = _get_transport(db, tenant_no, id)
if transport.approval_status not in ("none", "rejected"):
raise HTTPException(status_code=400, detail="当前状态不允许提交审批")
# 创建审批记录
for idx, approver_id in enumerate(payload.approver_ids):
from app.models.models import SysUser
approver = db.query(SysUser).filter(SysUser.id == approver_id).first()
if not approver:
raise HTTPException(status_code=400, detail=f"审批人不存在: {approver_id}")
approval = PlTransportApproval(
id=generate_uuid(),
tenant_no=tenant_no,
transport_id=id,
approver_id=approver_id,
approver_name=approver.nick_name,
approval_order=idx + 1,
status="pending",
create_by=user.id,
create_dept_id=user.dept_id,
)
db.add(approval)
transport.approval_status = "pending"
db.commit()
db.refresh(transport)
return transport
# =============================================================================
# 审批
# =============================================================================
@router.post("/approval/{id}", response_model=ApprovalRecordRead)
def process_approval(
id: str,
payload: ApprovalRequest,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> ApprovalRecordRead:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
approval = (
db.query(PlTransportApproval)
.filter(
PlTransportApproval.id == id,
PlTransportApproval.tenant_no == tenant_no,
PlTransportApproval.del_flag == 0,
)
.first()
)
if not approval:
raise HTTPException(status_code=404, detail="审批记录不存在")
if approval.status != "pending":
raise HTTPException(status_code=400, detail="该审批已处理")
# 更新审批状态
from datetime import datetime
approval.status = "approved" if payload.action == "approve" else "rejected"
approval.comment = payload.comment
approval.approval_time = datetime.now()
# 更新运输审批状态
transport = db.query(PlTransport).filter(PlTransport.id == approval.transport_id).first()
if transport:
if payload.action == "approve":
# 检查是否所有审批人都通过了
pending = (
db.query(PlTransportApproval)
.filter(
PlTransportApproval.transport_id == approval.transport_id,
PlTransportApproval.status == "pending",
PlTransportApproval.del_flag == 0,
)
.count()
)
if pending == 0:
transport.approval_status = "approved"
transport.transport_status = "pending"
else:
transport.approval_status = "rejected"
transport.transport_status = "draft"
db.commit()
db.refresh(approval)
return approval
# =============================================================================
# 获取运输的审批记录
# =============================================================================
@router.get("/{id}/approvals", response_model=list[ApprovalRecordRead])
def get_transport_approvals(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> list[ApprovalRecordRead]:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
approvals = (
db.query(PlTransportApproval)
.filter(
PlTransportApproval.transport_id == id,
PlTransportApproval.tenant_no == tenant_no,
PlTransportApproval.del_flag == 0,
)
.order_by(PlTransportApproval.approval_order)
.all()
)
return approvals
# =============================================================================
# 辅助函数
# =============================================================================
def _get_transport(db: Session, tenant_no: str, transport_id: str) -> PlTransport:
transport = (
db.query(PlTransport)
.filter(
PlTransport.id == transport_id,
PlTransport.tenant_no == tenant_no,
PlTransport.del_flag == 0,
)
.first()
)
if not transport:
raise HTTPException(status_code=404, detail="运输不存在")
return transport
+5 -1
View File
@@ -115,6 +115,9 @@ class Settings(BaseSettings):
# 临时文件目录
TEMP_FILE_DIR: str = "temp_files"
# 司机免登录 H5 页面 Origin(用于拼接 driverUrl)
PUBLIC_WEB_ORIGIN: str = "http://localhost:3006"
# 全量 API 请求日志(中间件写入 sys_api_request_log)
API_REQUEST_LOG_ENABLED: bool = True
API_REQUEST_LOG_MAX_BODY: int = 65536
@@ -146,7 +149,8 @@ class Settings(BaseSettings):
"/api/advances,"
"/api/reimburses,"
"/api/payments,"
"/api/attachments"
"/api/attachments,"
"/api/public/pl/transport"
)
class Config:
+6
View File
@@ -281,6 +281,8 @@ def _product_row_to_dict(row: CrmProduct) -> Dict[str, Any]:
"stock": row.stock if row.stock is not None else 0,
"lowStock": row.low_stock if row.low_stock is not None else 10,
"taxRate": float(row.tax_rate) if row.tax_rate is not None else 13.0,
"isToxic": int(row.is_toxic or 0),
"isExplosive": int(row.is_explosive or 0),
"status": row.status,
"description": row.description or "",
"images": row.images or "",
@@ -456,6 +458,8 @@ def create_product(
stock=kwargs.get("stock", 0),
low_stock=kwargs.get("low_stock", 10),
tax_rate=kwargs.get("tax_rate", Decimal("13.00")),
is_toxic=int(kwargs.get("is_toxic") or 0),
is_explosive=int(kwargs.get("is_explosive") or 0),
status=kwargs.get("status", "on"),
description=kwargs.get("description"),
images=kwargs.get("images"),
@@ -496,6 +500,8 @@ def update_product(
"stock",
"low_stock",
"tax_rate",
"is_toxic",
"is_explosive",
"status",
"description",
"images",
+5
View File
@@ -15,6 +15,7 @@ from app.core.api_crypto_middleware import ApiCryptoMiddleware
from app.models import models # noqa: F401
import app.models.bx_models # noqa: F401
import app.models.db_models # noqa: F401
import app.models.pl_models # noqa: F401
from app.api import (
public_router,
menu_router,
@@ -26,6 +27,8 @@ from app.api import (
bx_router,
db_router,
)
from app.api.pl import pl_router
from app.api.pl.public_transport import router as public_pl_transport_router
@asynccontextmanager
@@ -111,6 +114,7 @@ async def unhandled_exception_handler(request: Request, exc: Exception):
app.include_router(public_router, prefix=settings.API_V1_PREFIX)
app.include_router(public_pl_transport_router, prefix=settings.API_V1_PREFIX)
app.include_router(menu_router, prefix=settings.API_V1_PREFIX)
app.include_router(admin_router, prefix=settings.API_V1_PREFIX)
app.include_router(workflow_router, prefix=settings.API_V1_PREFIX)
@@ -118,6 +122,7 @@ app.include_router(leave_router, prefix=settings.API_V1_PREFIX)
app.include_router(crm_router, prefix=settings.API_V1_PREFIX)
app.include_router(bx_router, prefix=settings.API_V1_PREFIX)
app.include_router(db_router, prefix=settings.API_V1_PREFIX)
app.include_router(pl_router, prefix=settings.API_V1_PREFIX)
app.include_router(monitor_router, prefix=settings.API_V1_PREFIX)
+46
View File
@@ -27,6 +27,29 @@ from app.models.models import (
WfTask,
UserRole,
)
from app.models.pl_models import (
PlCarrier,
PlVehicle,
PlDriver,
PlPersonnel,
PlCert,
PlVehicleDriver,
PlVehiclePersonnel,
PlPlan,
PlPlanProduct,
PlPlanChange,
PlTransport,
PlTransportDbLink,
PlPlanTransport,
PlTransportApproval,
PlFreightSettlement,
PlFreightSettlementTransport,
PlRemittanceVoucher,
PlInventory,
PlInventoryTransaction,
PlInventoryWarning,
PlDocumentReminder,
)
User = SysUser
ApiRequestLog = SysApiRequestLog
@@ -34,6 +57,7 @@ ApiRequestLog = SysApiRequestLog
__all__ = [
"BaseModel",
"SoftDeleteModel",
# System models
"SysUser",
"SysRole",
"SysUserRole",
@@ -61,4 +85,26 @@ __all__ = [
"UserRole",
"User",
"ApiRequestLog",
# Transport Plan models
"PlCarrier",
"PlVehicle",
"PlDriver",
"PlPersonnel",
"PlCert",
"PlVehicleDriver",
"PlVehiclePersonnel",
"PlPlan",
"PlPlanProduct",
"PlPlanChange",
"PlTransport",
"PlTransportDbLink",
"PlPlanTransport",
"PlTransportApproval",
"PlFreightSettlement",
"PlFreightSettlementTransport",
"PlRemittanceVoucher",
"PlInventory",
"PlInventoryTransaction",
"PlInventoryWarning",
"PlDocumentReminder",
]
+3 -1
View File
@@ -1,7 +1,7 @@
"""报销(bx)模块数据模型 — 对齐 docs/sql/20260606_bx_tables.sql"""
from datetime import datetime
from sqlalchemy import BigInteger, Column, DateTime, DECIMAL, ForeignKey, Integer, SmallInteger, String
from sqlalchemy import BigInteger, Column, Date, DateTime, DECIMAL, ForeignKey, Integer, SmallInteger, String
from sqlalchemy.orm import relationship
from app.core.database import Base
@@ -154,6 +154,8 @@ class BxReimburseApply(Base):
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
apply_code = Column(String(32), nullable=False, comment="报销单号")
title = Column(String(256), nullable=False, comment="报销标题")
reimburse_date = Column(Date, nullable=False, comment="报销日期")
title_seq = Column(Integer, nullable=True, comment="标题序号(同租户同报销日期下自增)")
applicant_id = Column(String(64), nullable=False, comment="申请人用户ID")
applicant_name = Column(String(64), nullable=False, comment="申请人姓名")
expense_id = Column(String(64), nullable=False, comment="费用项目ID")
+2
View File
@@ -58,6 +58,8 @@ class CrmProduct(Base):
stock = Column(Integer, nullable=False, default=0, comment="库存数量")
low_stock = Column(Integer, nullable=False, default=10, comment="库存预警值")
tax_rate = Column(DECIMAL(5, 2), nullable=False, default=13.00, comment="税率(百分比)")
is_toxic = Column(SmallInteger, nullable=False, default=0, comment="是否易制毒 0-否 1-是")
is_explosive = Column(SmallInteger, nullable=False, default=0, comment="是否易制爆 0-否 1-是")
status = Column(String(3), nullable=False, default="on", comment="状态 on 上架 off 下架")
description = Column(Text, nullable=True, comment="产品描述")
images = Column(String(1000), nullable=True, comment="产品图片(多个用逗号分隔)")
+677
View File
@@ -0,0 +1,677 @@
"""运输计划管理模块数据模型"""
from datetime import datetime
from decimal import Decimal
from sqlalchemy import (
BigInteger,
Column,
DECIMAL,
Date,
DateTime,
Integer,
SmallInteger,
String,
Text,
CHAR,
ForeignKey,
)
from sqlalchemy.orm import relationship
from app.core.database import Base
# =============================================================================
# 1. 基础数据:承运商、车辆、司机
# =============================================================================
class PlCarrier(Base):
"""承运商表 pl_carrier"""
__tablename__ = "pl_carrier"
id = Column(String(64), primary_key=True, comment="主键ID")
carrier_name = Column(String(200), nullable=False, comment="承运商名称")
contact_name = Column(String(100), nullable=True, comment="联系人")
contact_phone = Column(String(32), nullable=True, comment="联系电话")
status = Column(CHAR(1), nullable=False, default="1", comment="合作状态 1-合作中 0-已终止")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlVehicle(Base):
"""车辆表 pl_vehicle"""
__tablename__ = "pl_vehicle"
id = Column(String(64), primary_key=True, comment="主键ID")
vehicle_type = Column(String(20), nullable=False, comment="车辆类型 self-自有 carrier-承运商")
carrier_id = Column(String(64), nullable=True, comment="承运商ID(类型为承运商时必填)")
carrier_name = Column(String(200), nullable=True, comment="承运商名称(冗余)")
license_plate = Column(String(20), nullable=False, unique=True, comment="车牌号")
default_driver_id = Column(String(64), nullable=True, comment="默认司机ID")
default_driver_name = Column(String(100), nullable=True, comment="默认司机姓名(冗余)")
load_capacity = Column(DECIMAL(10, 2), nullable=True, comment="载重(吨)")
vehicle_status = Column(String(20), nullable=False, default="available", comment="车辆状态 available-可用 maintaining-维修中 scrapped-报废")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlPersonnel(Base):
"""人员表 pl_personnel"""
__tablename__ = "pl_personnel"
id = Column(String(64), primary_key=True, comment="主键ID")
personnel_name = Column(String(100), nullable=False, comment="姓名")
phone_no = Column(String(32), nullable=True, comment="手机号(非必填)")
age = Column(Integer, nullable=True, comment="年龄")
id_card_no = Column(String(32), nullable=True, comment="身份证号")
status = Column(CHAR(1), nullable=False, default="1", comment="状态 1-在职 0-停用")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlCert(Base):
"""证书表 pl_cert"""
__tablename__ = "pl_cert"
id = Column(String(64), primary_key=True, comment="主键ID")
owner_type = Column(String(20), nullable=False, comment="归属类型 vehicle-车辆 personnel-人员")
owner_id = Column(String(64), nullable=False, comment="归属主体ID")
cert_name = Column(String(100), nullable=False, comment="证书名称")
cert_no = Column(String(64), nullable=True, comment="证号")
expire_date = Column(Date, nullable=True, comment="有效期")
remind_days = Column(Integer, nullable=False, default=30, comment="提前提醒天数")
attachment_urls = Column(String(2000), nullable=True, comment="附件URL(逗号分隔)")
status = Column(String(20), nullable=False, default="valid", comment="状态 valid-有效 expired-已过期 revoked-已作废")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlDriver(Base):
"""司机表 pl_driver(兼容旧表,迁移后逐步废弃)"""
__tablename__ = "pl_driver"
id = Column(String(64), primary_key=True, comment="主键ID")
driver_name = Column(String(100), nullable=False, comment="姓名")
phone_no = Column(String(32), nullable=False, comment="手机号")
id_card_no = Column(String(32), nullable=True, comment="身份证号")
driving_license_no = Column(String(32), nullable=True, comment="驾驶证号")
driving_license_expire = Column(Date, nullable=True, comment="驾驶证有效期")
vehicle_license_no = Column(String(32), nullable=True, comment="行驶证号")
vehicle_license_expire = Column(Date, nullable=True, comment="行驶证有效期")
hazmat_cert_no = Column(String(32), nullable=True, comment="危化品证号")
hazmat_cert_expire = Column(Date, nullable=True, comment="危化品证有效期")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlVehiclePersonnel(Base):
"""车辆-人员关联表 pl_vehicle_personnel"""
__tablename__ = "pl_vehicle_personnel"
id = Column(String(64), primary_key=True, comment="主键ID")
vehicle_id = Column(String(64), nullable=False, comment="车辆ID")
personnel_id = Column(String(64), nullable=False, comment="人员ID")
role = Column(String(20), nullable=False, default="driver", comment="角色 driver-司机 escort-押运员")
is_default = Column(SmallInteger, nullable=False, default=0, comment="是否默认司机 0-否 1-是")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="关联备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlVehicleDriver(Base):
"""车辆-司机关联表 pl_vehicle_driver(兼容旧表)"""
__tablename__ = "pl_vehicle_driver"
id = Column(String(64), primary_key=True, comment="主键ID")
vehicle_id = Column(String(64), nullable=False, comment="车辆ID")
driver_id = Column(String(64), nullable=False, comment="司机ID")
is_default = Column(SmallInteger, nullable=False, default=0, comment="是否默认 0-否 1-是")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
# =============================================================================
# 2. 计划管理:计划主表、产品明细、变更记录
# =============================================================================
class PlPlan(Base):
"""计划主表 pl_plan"""
__tablename__ = "pl_plan"
id = Column(String(64), primary_key=True, comment="主键ID")
# 编号信息
plan_no = Column(String(32), nullable=False, unique=True, comment="计划订单编号 SXDDHYYYYMMDD######")
plan_date = Column(Date, nullable=False, comment="计划日期")
# 基本信息
belongs_company = Column(String(20), nullable=False, comment="归属公司 shanxia-安庆山峡 yundong-安徽云栋")
plan_type = Column(String(20), nullable=False, comment="单据类型 direct-直销单 inbound-入库单 outbound-出库单")
follow_status = Column(String(30), nullable=False, default="draft", comment="跟进状态")
transport_status = Column(String(20), nullable=False, default="pending", comment="运输安排状态 pending-待安排 arranged-已安排")
archive_status = Column(String(20), nullable=False, default="unarchived", comment="归档状态 unarchived-未归档 archived-已归档")
complete_status = Column(String(10), nullable=False, default="no", comment="完成状态 yes-是 no-否")
# 合同关联
contract_id = Column(String(64), nullable=True, comment="CRM合同ID")
contract_no = Column(String(50), nullable=True, comment="合同编号")
# 供应商与目的地
supplier_id = Column(String(64), nullable=True, comment="供应商ID")
supplier_name = Column(String(200), nullable=True, comment="供应商名称")
destination_id = Column(String(64), nullable=True, comment="目的地ID")
destination_name = Column(String(200), nullable=True, comment="目的地名称")
# 客户信息(冗余自合同)
customer_id = Column(String(64), nullable=True, comment="客户ID")
customer_name = Column(String(200), nullable=True, comment="客户名称")
contact_name = Column(String(100), nullable=True, comment="联系人")
contact_phone = Column(String(32), nullable=True, comment="联系电话")
party_a = Column(String(200), nullable=True, comment="甲方")
party_b = Column(String(200), nullable=True, comment="乙方")
# 合同有效期
contract_start_date = Column(Date, nullable=True, comment="合同开始日期")
contract_end_date = Column(Date, nullable=True, comment="合同结束日期")
# 送货与结算
delivery_method = Column(String(20), nullable=True, comment="送货方式 self_pick-山峡自提 one_ticket-一票制 customer_pick-客户自提")
settlement_method = Column(String(50), nullable=True, comment="结算方式")
# 运输信息
has_freight = Column(SmallInteger, nullable=False, default=0, comment="是否有运输费用 0-否 1-是")
pickup_address = Column(String(500), nullable=True, comment="取货地址")
pickup_time = Column(DateTime, nullable=True, comment="取货时间")
pickup_notes = Column(String(500), nullable=True, comment="取货注意事项")
destination_address = Column(String(500), nullable=True, comment="目的地地址")
delivery_time = Column(DateTime, nullable=True, comment="送达时间")
destination_notes = Column(String(500), nullable=True, comment="目的地注意事项")
transport_id = Column(String(64), nullable=True, comment="运输ID")
transport_no = Column(String(32), nullable=True, comment="运输编号")
vehicle_id = Column(String(64), nullable=True, comment="车辆ID")
license_plate = Column(String(20), nullable=True, comment="车牌号")
driver_id = Column(String(64), nullable=True, comment="司机ID")
driver_name = Column(String(100), nullable=True, comment="司机姓名")
# 金额汇总
total_amount = Column(DECIMAL(15, 2), nullable=False, default=0, comment="计划总金额")
freight_amount = Column(DECIMAL(15, 2), nullable=False, default=0, comment="运费合计")
# 通知信息
notify_message = Column(Text, nullable=True, comment="通知信息(标准模板)")
# 跟进人
follow_user_id = Column(String(64), nullable=True, comment="跟进人ID")
follow_user_name = Column(String(100), nullable=True, comment="跟进人姓名")
# 公共字段
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlPlanProduct(Base):
"""计划产品明细表 pl_plan_product"""
__tablename__ = "pl_plan_product"
id = Column(String(64), primary_key=True, comment="主键ID")
plan_id = Column(String(64), nullable=False, comment="计划ID")
# 产品信息
product_id = Column(String(64), nullable=False, comment="产品ID")
product_no = Column(String(50), nullable=False, comment="产品编号")
product_name = Column(String(200), nullable=False, comment="产品名称")
model = Column(String(100), nullable=True, comment="规格型号")
unit = Column(String(20), nullable=False, default="吨", comment="单位")
category_name = Column(String(200), nullable=True, comment="产品分类")
package_spec = Column(String(200), nullable=True, comment="包装规格")
delivery_method = Column(String(50), nullable=True, comment="送货方式")
quantity = Column(DECIMAL(15, 3), nullable=True, comment="合同数量")
actual_qty = Column(DECIMAL(15, 3), nullable=True, comment="实际数量")
tax_price = Column(DECIMAL(15, 4), nullable=True, comment="含税单价")
tax_amount = Column(DECIMAL(15, 2), nullable=True, comment="税费")
tax_subtotal = Column(DECIMAL(15, 2), nullable=True, comment="含税总价")
# 产品属性(冗余自产品主数据)
is_explosive = Column(SmallInteger, nullable=False, default=0, comment="是否易制爆 0-否 1-是")
is_toxic = Column(SmallInteger, nullable=False, default=0, comment="是否易制毒 0-否 1-是")
# 购买证/运输证
purchase_cert_url = Column(String(500), nullable=True, comment="购买证URL")
transport_cert_url = Column(String(500), nullable=True, comment="运输证URL")
# 入库信息
inbound_estimate_qty = Column(DECIMAL(15, 3), nullable=True, comment="入库预估数")
inbound_qty = Column(DECIMAL(15, 3), nullable=True, comment="入库数")
inbound_price = Column(DECIMAL(15, 4), nullable=True, comment="入库价")
inbound_amount = Column(DECIMAL(15, 2), nullable=True, comment="入库金额")
# 出库信息
outbound_estimate_qty = Column(DECIMAL(15, 3), nullable=True, comment="出库预估数")
outbound_qty = Column(DECIMAL(15, 3), nullable=True, comment="出库数")
outbound_price = Column(DECIMAL(15, 4), nullable=True, comment="出库单价")
outbound_amount = Column(DECIMAL(15, 2), nullable=True, comment="出库金额")
# 公共字段
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlPlanChange(Base):
"""计划变更记录表 pl_plan_change"""
__tablename__ = "pl_plan_change"
id = Column(String(64), primary_key=True, comment="主键ID")
plan_id = Column(String(64), nullable=False, comment="计划ID")
change_type = Column(String(30), nullable=False, comment="变更类型")
change_content = Column(Text, nullable=True, comment="变更内容")
change_user_id = Column(String(64), nullable=True, comment="变更人ID")
change_user_name = Column(String(100), nullable=True, comment="变更人姓名")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
# =============================================================================
# 3. 运输管理:运输表、审批记录
# =============================================================================
class PlTransport(Base):
"""运输表 pl_transport"""
__tablename__ = "pl_transport"
id = Column(String(64), primary_key=True, comment="主键ID")
transport_no = Column(String(32), nullable=False, unique=True, comment="运输编号 SXYS######")
# 车辆与司机
vehicle_id = Column(String(64), nullable=True, comment="车辆ID")
license_plate = Column(String(20), nullable=True, comment="车牌号")
driver_id = Column(String(64), nullable=True, comment="司机ID")
driver_name = Column(String(100), nullable=True, comment="司机姓名")
driver_phone = Column(String(32), nullable=True, comment="司机电话")
# 承运商
carrier_id = Column(String(64), nullable=True, comment="承运商ID")
carrier_name = Column(String(200), nullable=True, comment="承运商名称")
# 运输信息
transport_medium = Column(String(100), nullable=True, comment="运输介质")
start_point = Column(String(200), nullable=True, comment="运输起点")
end_point = Column(String(200), nullable=True, comment="运输终点")
distance_km = Column(DECIMAL(10, 2), nullable=True, comment="运输公里数")
unit = Column(String(20), nullable=True, comment="计量单位 吨/趟")
transport_qty = Column(DECIMAL(15, 3), nullable=True, comment="运输量(按重量计费基数)")
# 运费
freight_price = Column(DECIMAL(15, 4), nullable=True, comment="运输单价")
freight_amount = Column(DECIMAL(15, 2), nullable=False, default=0, comment="运输费用")
freight_type = Column(String(20), nullable=False, default="by_weight", comment="运费计算方式 by_weight-按重量 by_trip-按趟次")
has_invoice = Column(SmallInteger, nullable=False, default=0, comment="是否开票 0-否 1-是")
# 二维码
qr_code = Column(String(500), nullable=True, comment="二维码内容")
qr_expire_date = Column(Date, nullable=True, comment="二维码有效期")
driver_access_token = Column(String(64), nullable=True, comment="司机免登录访问令牌")
# 运输状态
transport_status = Column(String(20), nullable=False, default="draft", comment="运输状态 draft-草稿 pending-待执行 executing-执行中 completed-已完成 cancelled-已取消")
approval_status = Column(String(20), nullable=False, default="none", comment="审批状态 none-无需 pending-审批中 approved-已通过 rejected-已拒绝")
# 司机回传信息
feedback_time = Column(DateTime, nullable=True, comment="回传时间")
feedback_qty = Column(DECIMAL(15, 3), nullable=True, comment="回传数量")
feedback_images = Column(Text, nullable=True, comment="回传图片URLs(JSON数组)")
feedback_remark = Column(String(500), nullable=True, comment="回传备注")
# 公共字段
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlTransportDbLink(Base):
"""运输-地磅出入库关联 pl_transport_db_link"""
__tablename__ = "pl_transport_db_link"
id = Column(String(64), primary_key=True, comment="主键ID")
transport_id = Column(String(64), nullable=False, comment="运输单ID")
plan_id = Column(String(64), nullable=False, comment="运输计划ID")
plan_product_id = Column(String(64), nullable=False, comment="计划产品行ID")
db_purchase_plan_id = Column(String(64), nullable=False, comment="地磅计划ID")
db_inventory_id = Column(String(64), nullable=False, comment="出入库单ID")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlPlanTransport(Base):
"""计划-运输关联表 pl_plan_transport"""
__tablename__ = "pl_plan_transport"
id = Column(String(64), primary_key=True, comment="主键ID")
plan_id = Column(String(64), nullable=False, comment="计划ID")
transport_id = Column(String(64), nullable=False, comment="运输ID")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlTransportApproval(Base):
"""运输审批记录表 pl_transport_approval"""
__tablename__ = "pl_transport_approval"
id = Column(String(64), primary_key=True, comment="主键ID")
transport_id = Column(String(64), nullable=False, comment="运输ID")
approver_id = Column(String(64), nullable=False, comment="审批人ID")
approver_name = Column(String(100), nullable=False, comment="审批人姓名")
approval_order = Column(Integer, nullable=False, comment="审批顺序")
status = Column(String(20), nullable=False, default="pending", comment="审批状态 pending-待审批 approved-已通过 rejected-已拒绝")
comment = Column(String(500), nullable=True, comment="审批意见")
approval_time = Column(DateTime, nullable=True, comment="审批时间")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
# =============================================================================
# 4. 运费结算
# =============================================================================
class PlFreightSettlement(Base):
"""运费结算表 pl_freight_settlement"""
__tablename__ = "pl_freight_settlement"
id = Column(String(64), primary_key=True, comment="主键ID")
settlement_no = Column(String(32), nullable=False, unique=True, comment="结算单编号")
# 结算金额
total_freight = Column(DECIMAL(15, 2), nullable=False, default=0, comment="运费合计")
invoice_amount = Column(DECIMAL(15, 2), nullable=True, comment="发票金额")
# 发票信息
invoice_no = Column(String(50), nullable=True, comment="发票号")
invoice_date = Column(Date, nullable=True, comment="开票日期")
# 结算状态
settlement_status = Column(String(20), nullable=False, default="pending", comment="结算状态 pending-待提交 submitted-已提交 approved-审核通过 confirmed-已确认")
# 公共字段
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlFreightSettlementTransport(Base):
"""结算单-运输关联表 pl_freight_settlement_transport"""
__tablename__ = "pl_freight_settlement_transport"
id = Column(String(64), primary_key=True, comment="主键ID")
settlement_id = Column(String(64), nullable=False, comment="结算单ID")
transport_id = Column(String(64), nullable=False, comment="运输ID")
freight_amount = Column(DECIMAL(15, 2), nullable=False, comment="运费金额")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlRemittanceVoucher(Base):
"""汇款凭证表 pl_remittance_voucher"""
__tablename__ = "pl_remittance_voucher"
id = Column(String(64), primary_key=True, comment="主键ID")
settlement_id = Column(String(64), nullable=False, comment="结算单ID")
voucher_no = Column(String(32), nullable=True, comment="凭证编号")
remittance_date = Column(Date, nullable=True, comment="汇款日期")
remittance_amount = Column(DECIMAL(15, 2), nullable=True, comment="汇款金额")
voucher_urls = Column(Text, nullable=True, comment="凭证文件URLs(JSON数组)")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
# =============================================================================
# 5. 库存管理
# =============================================================================
class PlInventory(Base):
"""库存表 pl_inventory"""
__tablename__ = "pl_inventory"
id = Column(String(64), primary_key=True, comment="主键ID")
product_id = Column(String(64), nullable=False, comment="产品ID")
product_no = Column(String(50), nullable=False, comment="产品编号")
product_name = Column(String(200), nullable=False, comment="产品名称")
model = Column(String(100), nullable=True, comment="规格型号")
unit = Column(String(20), nullable=False, default="吨", comment="单位")
# 库存数量与金额
stock_qty = Column(DECIMAL(15, 3), nullable=False, default=0, comment="库存数量")
stock_amount = Column(DECIMAL(15, 2), nullable=False, default=0, comment="库存金额")
# 预警阈值
low_stock_warning = Column(DECIMAL(15, 3), nullable=True, comment="最低库存预警值")
high_stock_warning = Column(DECIMAL(15, 3), nullable=True, comment="最高库存预警值")
# 公共字段
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlInventoryTransaction(Base):
"""库存流水表 pl_inventory_transaction"""
__tablename__ = "pl_inventory_transaction"
id = Column(String(64), primary_key=True, comment="主键ID")
product_id = Column(String(64), nullable=False, comment="产品ID")
product_name = Column(String(200), nullable=False, comment="产品名称")
transaction_type = Column(String(20), nullable=False, comment="事务类型 inbound-入库 outbound-出库")
plan_id = Column(String(64), nullable=True, comment="计划ID")
plan_no = Column(String(32), nullable=True, comment="计划编号")
# 数量与价格
qty = Column(DECIMAL(15, 3), nullable=False, comment="变动数量(正数入库/负数出库)")
unit_price = Column(DECIMAL(15, 4), nullable=False, comment="单价")
amount = Column(DECIMAL(15, 2), nullable=False, comment="金额")
stock_after = Column(DECIMAL(15, 3), nullable=False, comment="变动后库存")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlInventoryWarning(Base):
"""库存预警表 pl_inventory_warning"""
__tablename__ = "pl_inventory_warning"
id = Column(String(64), primary_key=True, comment="主键ID")
product_id = Column(String(64), nullable=False, comment="产品ID")
product_name = Column(String(200), nullable=False, comment="产品名称")
warning_type = Column(String(20), nullable=False, comment="预警类型 low-低于最低 high-高于最高")
current_qty = Column(DECIMAL(15, 3), nullable=False, comment="当前库存")
threshold_value = Column(DECIMAL(15, 3), nullable=False, comment="阈值")
status = Column(String(20), nullable=False, default="pending", comment="状态 pending-待处理 resolved-已处理")
resolve_time = Column(DateTime, nullable=True, comment="处理时间")
resolve_remark = Column(String(500), nullable=True, comment="处理备注")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlDocumentReminder(Base):
"""证件到期提醒表 pl_document_reminder"""
__tablename__ = "pl_document_reminder"
id = Column(String(64), primary_key=True, comment="主键ID")
cert_id = Column(String(64), nullable=True, comment="证书ID")
owner_type = Column(String(20), nullable=True, comment="归属类型 vehicle/personnel")
owner_id = Column(String(64), nullable=True, comment="归属主体ID")
owner_label = Column(String(200), nullable=True, comment="归属展示名(车牌/姓名)")
driver_id = Column(String(64), nullable=True, comment="司机/人员ID(兼容)")
driver_name = Column(String(100), nullable=True, comment="司机/人员姓名(兼容)")
document_type = Column(String(100), nullable=False, comment="证件类型/证书名称")
document_no = Column(String(50), nullable=True, comment="证件号")
expire_date = Column(Date, nullable=False, comment="到期日期")
days_remaining = Column(Integer, nullable=False, comment="剩余天数")
status = Column(String(20), nullable=False, default="pending", comment="状态 pending-待处理 resolved-已处理")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
+9 -1
View File
@@ -1,5 +1,5 @@
"""bx 原系统 API 响应包装(code=0 / msg / data.rows),与门户 success_response 分离。"""
from datetime import datetime
from datetime import date, datetime
from typing import Annotated, Generic, List, Optional, TypeVar
from pydantic import BaseModel, ConfigDict, PlainSerializer
@@ -14,8 +14,16 @@ def _dt_to_str(v: Optional[datetime]) -> Optional[str]:
return v.strftime("%Y-%m-%d %H:%M:%S")
def _date_to_str(v: Optional[date]) -> Optional[str]:
if v is None:
return None
return v.strftime("%Y-%m-%d")
DatetimeToStr = Annotated[datetime, PlainSerializer(_dt_to_str, return_type=str)]
OptDatetimeToStr = Annotated[Optional[datetime], PlainSerializer(_dt_to_str, return_type=Optional[str])]
DateToStr = Annotated[date, PlainSerializer(_date_to_str, return_type=str)]
OptDateToStr = Annotated[Optional[date], PlainSerializer(_date_to_str, return_type=Optional[str])]
class PagedQuery(BaseModel):
+5 -1
View File
@@ -3,7 +3,7 @@ from typing import List, Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator
from pydantic.alias_generators import to_camel
from app.schemas.bx.common import DatetimeToStr, OptDatetimeToStr
from app.schemas.bx.common import DatetimeToStr, OptDateToStr, OptDatetimeToStr
def _coerce_id(value):
@@ -42,6 +42,7 @@ class ReimburseApplyCreate(BaseModel):
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
title: Optional[str] = None
reimburse_date: Optional[str] = None
details: List[ReimburseDetailCreate] = Field(..., min_length=1)
remark: Optional[str] = None
@@ -57,6 +58,8 @@ class ReimburseApplyUpdate(BaseModel):
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
details: Optional[List[ReimburseDetailCreate]] = None
title: Optional[str] = None
reimburse_date: Optional[str] = None
remark: Optional[str] = None
@@ -68,6 +71,7 @@ class ReimburseApplyOut(BaseModel):
applicant_id: str
applicant_name: str
title: str
reimburse_date: OptDateToStr = None
expense_id: Optional[str] = None
expense_name: str
amount: float
+4
View File
@@ -88,6 +88,8 @@ class ProductCreateBody(BaseModel):
stock: int = Field(default=0, description="库存数量")
low_stock: int = Field(default=10, alias="lowStock", description="库存预警值")
tax_rate: Decimal = Field(default=Decimal("13.00"), alias="taxRate", description="税率(%)")
is_toxic: int = Field(default=0, alias="isToxic", description="是否易制毒 0-否 1-是")
is_explosive: int = Field(default=0, alias="isExplosive", description="是否易制爆 0-否 1-是")
status: str = Field(default="on", description="状态 on=上架 off=下架")
description: Optional[str] = Field(default=None, description="产品描述")
images: Optional[str] = Field(default=None, description="产品图片(逗号分隔 URL)")
@@ -119,6 +121,8 @@ class ProductUpdateBody(BaseModel):
stock: Optional[int] = Field(default=None, description="库存数量")
low_stock: Optional[int] = Field(default=None, alias="lowStock", description="库存预警值")
tax_rate: Optional[Decimal] = Field(default=None, alias="taxRate", description="税率(%)")
is_toxic: Optional[int] = Field(default=None, alias="isToxic", description="是否易制毒")
is_explosive: Optional[int] = Field(default=None, alias="isExplosive", description="是否易制爆")
status: Optional[str] = Field(default=None, description="状态")
description: Optional[str] = Field(default=None, description="产品描述")
images: Optional[str] = Field(default=None, description="产品图片(逗号分隔 URL)")
+169
View File
@@ -0,0 +1,169 @@
"""运输计划管理 - Pydantic Schema"""
from app.schemas.pl.base_data import (
CarrierBase,
CarrierCreate,
CarrierRead,
CarrierUpdate,
CertRead,
CertRow,
DriverBase,
DriverCreate,
DriverRead,
DriverUpdate,
PersonnelBase,
PersonnelCreate,
PersonnelDetailRead,
PersonnelRead,
PersonnelUpdate,
VehicleBase,
VehicleCreate,
VehicleDetailRead,
VehicleDriverCreate,
VehicleDriverRead,
VehiclePersonnelRow,
VehicleRead,
VehicleUpdate,
)
from app.schemas.pl.plan import (
PlanBase,
PlanProductBase,
PlanProductCreate,
PlanProductUpdate,
PlanProductRead,
PlanCreate,
PlanUpdate,
PlanRead,
PlanWithProducts,
PlanListQuery,
PlanListResponse,
CreateFromContractRequest,
PlanCreateFull,
PlanTransportCreateBlock,
)
from app.schemas.pl.transport import (
TransportBase,
TransportCreate,
TransportUpdate,
TransportRead,
TransportWithPlans,
TransportFeedback,
ApprovalSubmit,
ApprovalRequest,
ApprovalRecordRead,
TransportListQuery,
TransportListResponse,
)
from app.schemas.pl.freight import (
FreightSettlementBase,
FreightSettlementCreate,
FreightSettlementUpdate,
FreightSettlementRead,
FreightSettlementWithTransports,
FreightSettlementTransportRead,
RemittanceVoucherCreate,
RemittanceVoucherRead,
FreightSettlementListQuery,
FreightSettlementListResponse,
)
from app.schemas.pl.inventory import (
InventoryRead,
InventoryTransactionRead,
InventoryWarningRead,
InventoryWarningUpdate,
InventoryWarningThreshold,
DocumentReminderRead,
DocumentReminderUpdate,
InventoryLedgerQuery,
InventoryLedgerResponse,
InventoryTransactionQuery,
InventoryTransactionResponse,
InventorySummaryQuery,
InventorySummaryItem,
InventorySummaryResponse,
TransportStatsQuery,
TransportStatsItem,
TransportStatsResponse,
)
__all__ = [
# Base data
"CarrierBase",
"VehicleBase",
"DriverBase",
"VehicleDriverCreate",
"VehiclePersonnelRow",
"CertRow",
"CertRead",
"CarrierCreate",
"CarrierUpdate",
"CarrierRead",
"VehicleCreate",
"VehicleUpdate",
"VehicleRead",
"VehicleDetailRead",
"PersonnelBase",
"PersonnelCreate",
"PersonnelUpdate",
"PersonnelRead",
"PersonnelDetailRead",
"DriverCreate",
"DriverUpdate",
"DriverRead",
"VehicleDriverRead",
# Plan
"PlanBase",
"PlanProductBase",
"PlanProductCreate",
"PlanProductUpdate",
"PlanProductRead",
"PlanCreate",
"PlanUpdate",
"PlanRead",
"PlanWithProducts",
"PlanListQuery",
"PlanListResponse",
"CreateFromContractRequest",
"PlanCreateFull",
"PlanTransportCreateBlock",
# Transport
"TransportBase",
"TransportCreate",
"TransportUpdate",
"TransportRead",
"TransportWithPlans",
"TransportFeedback",
"ApprovalSubmit",
"ApprovalRequest",
"ApprovalRecordRead",
"TransportListQuery",
"TransportListResponse",
# Freight
"FreightSettlementBase",
"FreightSettlementCreate",
"FreightSettlementUpdate",
"FreightSettlementRead",
"FreightSettlementWithTransports",
"FreightSettlementTransportRead",
"RemittanceVoucherCreate",
"RemittanceVoucherRead",
"FreightSettlementListQuery",
"FreightSettlementListResponse",
# Inventory
"InventoryRead",
"InventoryTransactionRead",
"InventoryWarningRead",
"InventoryWarningUpdate",
"InventoryWarningThreshold",
"DocumentReminderRead",
"DocumentReminderUpdate",
"InventoryLedgerQuery",
"InventoryLedgerResponse",
"InventoryTransactionQuery",
"InventoryTransactionResponse",
"InventorySummaryQuery",
"InventorySummaryItem",
"InventorySummaryResponse",
"TransportStatsQuery",
"TransportStatsItem",
"TransportStatsResponse",
]
+258
View File
@@ -0,0 +1,258 @@
"""运输计划管理 - 基础数据 Schema(承运商、车辆、人员、证书)"""
from datetime import date, datetime
from decimal import Decimal
from typing import Optional
from pydantic import BaseModel, Field
# =============================================================================
# 承运商 Schema
# =============================================================================
class CarrierBase(BaseModel):
carrier_name: str = Field(..., max_length=200, alias="carrierName", description="承运商名称")
contact_name: Optional[str] = Field(default=None, max_length=100, alias="contactName", description="联系人")
contact_phone: Optional[str] = Field(default=None, max_length=32, alias="contactPhone", description="联系电话")
status: str = Field(default="1", max_length=1, description="合作状态 1-合作中 0-已终止")
remark: Optional[str] = Field(default=None, description="备注")
class CarrierCreate(CarrierBase):
model_config = {"populate_by_name": True}
class CarrierUpdate(BaseModel):
carrier_name: Optional[str] = Field(default=None, max_length=200, alias="carrierName")
contact_name: Optional[str] = Field(default=None, max_length=100, alias="contactName")
contact_phone: Optional[str] = Field(default=None, max_length=32, alias="contactPhone")
status: Optional[str] = Field(default=None, max_length=1)
remark: Optional[str] = None
model_config = {"populate_by_name": True}
class CarrierRead(CarrierBase):
id: str
tenant_no: str = Field(alias="tenantNo")
order_num: Optional[int] = Field(default=None, alias="orderNum")
create_by: Optional[str] = Field(default=None, alias="createBy")
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
create_time: datetime = Field(alias="createTime")
update_by: Optional[str] = Field(default=None, alias="updateBy")
update_time: datetime = Field(alias="updateTime")
del_flag: int = Field(default=0, alias="delFlag")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 子表行 Schema
# =============================================================================
class VehiclePersonnelRow(BaseModel):
personnel_id: Optional[str] = Field(default=None, alias="personnelId")
personnel_name: str = Field(..., alias="personnelName")
phone_no: Optional[str] = Field(default=None, alias="phoneNo")
age: Optional[int] = None
role: str = Field(..., description="driver|escort")
is_default: int = Field(default=0, alias="isDefault")
remark: Optional[str] = None
model_config = {"populate_by_name": True}
class CertRow(BaseModel):
cert_id: Optional[str] = Field(default=None, alias="certId")
cert_name: str = Field(..., alias="certName")
cert_no: Optional[str] = Field(default=None, alias="certNo")
expire_date: Optional[date] = Field(default=None, alias="expireDate")
remind_days: int = Field(default=30, alias="remindDays")
attachment_urls: Optional[str] = Field(default=None, alias="attachmentUrls")
model_config = {"populate_by_name": True}
class CertRead(CertRow):
id: str
owner_type: str = Field(alias="ownerType")
owner_id: str = Field(alias="ownerId")
status: str
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
update_time: datetime = Field(alias="updateTime")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 车辆 Schema
# =============================================================================
class VehicleBase(BaseModel):
vehicle_type: str = Field(..., alias="vehicleType", description="车辆类型 self-自有 carrier-承运商")
carrier_id: Optional[str] = Field(default=None, alias="carrierId", description="承运商ID")
carrier_name: Optional[str] = Field(default=None, max_length=200, alias="carrierName", description="承运商名称")
license_plate: str = Field(..., max_length=20, alias="licensePlate", description="车牌号")
default_driver_id: Optional[str] = Field(default=None, alias="defaultDriverId", description="默认司机ID(只读兼容)")
default_driver_name: Optional[str] = Field(default=None, max_length=100, alias="defaultDriverName", description="默认司机姓名(只读兼容)")
load_capacity: Optional[Decimal] = Field(default=None, alias="loadCapacity", description="载重(吨)")
vehicle_status: str = Field(default="available", max_length=20, alias="vehicleStatus", description="车辆状态")
remark: Optional[str] = None
class VehicleCreate(VehicleBase):
personnel_list: list[VehiclePersonnelRow] = Field(default_factory=list, alias="personnelList")
cert_list: list[CertRow] = Field(default_factory=list, alias="certList")
model_config = {"populate_by_name": True}
class VehicleUpdate(BaseModel):
vehicle_type: Optional[str] = Field(default=None, max_length=20, alias="vehicleType")
carrier_id: Optional[str] = Field(default=None, alias="carrierId")
carrier_name: Optional[str] = Field(default=None, max_length=200, alias="carrierName")
license_plate: Optional[str] = Field(default=None, max_length=20, alias="licensePlate")
load_capacity: Optional[Decimal] = Field(default=None, alias="loadCapacity")
vehicle_status: Optional[str] = Field(default=None, max_length=20, alias="vehicleStatus")
remark: Optional[str] = None
personnel_list: Optional[list[VehiclePersonnelRow]] = Field(default=None, alias="personnelList")
cert_list: Optional[list[CertRow]] = Field(default=None, alias="certList")
model_config = {"populate_by_name": True}
class VehicleRead(VehicleBase):
id: str
tenant_no: str = Field(alias="tenantNo")
order_num: Optional[int] = Field(default=None, alias="orderNum")
personnel_summary: Optional[str] = Field(default=None, alias="personnelSummary")
create_by: Optional[str] = Field(default=None, alias="createBy")
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
create_time: datetime = Field(alias="createTime")
update_by: Optional[str] = Field(default=None, alias="updateBy")
update_time: datetime = Field(alias="updateTime")
del_flag: int = Field(default=0, alias="delFlag")
model_config = {"from_attributes": True, "populate_by_name": True}
class VehicleDetailRead(VehicleRead):
personnel_list: list[VehiclePersonnelRow] = Field(default_factory=list, alias="personnelList")
cert_list: list[CertRead] = Field(default_factory=list, alias="certList")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 人员 Schema
# =============================================================================
class PersonnelBase(BaseModel):
personnel_name: str = Field(..., max_length=100, alias="personnelName", description="姓名")
phone_no: Optional[str] = Field(default=None, max_length=32, alias="phoneNo", description="手机号")
age: Optional[int] = Field(default=None, description="年龄")
id_card_no: Optional[str] = Field(default=None, max_length=32, alias="idCardNo", description="身份证号")
status: str = Field(default="1", max_length=1, description="状态 1-在职 0-停用")
remark: Optional[str] = None
class PersonnelCreate(PersonnelBase):
cert_list: list[CertRow] = Field(default_factory=list, alias="certList")
model_config = {"populate_by_name": True}
class PersonnelUpdate(BaseModel):
personnel_name: Optional[str] = Field(default=None, max_length=100, alias="personnelName")
phone_no: Optional[str] = Field(default=None, max_length=32, alias="phoneNo")
age: Optional[int] = None
id_card_no: Optional[str] = Field(default=None, max_length=32, alias="idCardNo")
status: Optional[str] = Field(default=None, max_length=1)
remark: Optional[str] = None
cert_list: Optional[list[CertRow]] = Field(default=None, alias="certList")
model_config = {"populate_by_name": True}
class PersonnelRead(PersonnelBase):
id: str
tenant_no: str = Field(alias="tenantNo")
order_num: Optional[int] = Field(default=None, alias="orderNum")
nearest_expire_date: Optional[date] = Field(default=None, alias="nearestExpireDate")
create_by: Optional[str] = Field(default=None, alias="createBy")
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
create_time: datetime = Field(alias="createTime")
update_by: Optional[str] = Field(default=None, alias="updateBy")
update_time: datetime = Field(alias="updateTime")
del_flag: int = Field(default=0, alias="delFlag")
model_config = {"from_attributes": True, "populate_by_name": True}
class PersonnelDetailRead(PersonnelRead):
cert_list: list[CertRead] = Field(default_factory=list, alias="certList")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 司机 Schema(兼容旧 API)
# =============================================================================
class DriverBase(BaseModel):
driver_name: str = Field(..., max_length=100, alias="driverName", description="姓名")
phone_no: Optional[str] = Field(default=None, max_length=32, alias="phoneNo", description="手机号")
id_card_no: Optional[str] = Field(default=None, max_length=32, alias="idCardNo", description="身份证号")
driving_license_no: Optional[str] = Field(default=None, max_length=32, alias="drivingLicenseNo", description="驾驶证号")
driving_license_expire: Optional[date] = Field(default=None, alias="drivingLicenseExpire", description="驾驶证有效期")
vehicle_license_no: Optional[str] = Field(default=None, max_length=32, alias="vehicleLicenseNo", description="行驶证号")
vehicle_license_expire: Optional[date] = Field(default=None, alias="vehicleLicenseExpire", description="行驶证有效期")
hazmat_cert_no: Optional[str] = Field(default=None, max_length=32, alias="hazmatCertNo", description="危化品证号")
hazmat_cert_expire: Optional[date] = Field(default=None, alias="hazmatCertExpire", description="危化品证有效期")
remark: Optional[str] = None
class DriverCreate(DriverBase):
model_config = {"populate_by_name": True}
class DriverUpdate(BaseModel):
driver_name: Optional[str] = Field(default=None, max_length=100, alias="driverName")
phone_no: Optional[str] = Field(default=None, max_length=32, alias="phoneNo")
id_card_no: Optional[str] = Field(default=None, max_length=32, alias="idCardNo")
driving_license_no: Optional[str] = Field(default=None, max_length=32, alias="drivingLicenseNo")
driving_license_expire: Optional[date] = Field(default=None, alias="drivingLicenseExpire")
vehicle_license_no: Optional[str] = Field(default=None, max_length=32, alias="vehicleLicenseNo")
vehicle_license_expire: Optional[date] = Field(default=None, alias="vehicleLicenseExpire")
hazmat_cert_no: Optional[str] = Field(default=None, max_length=32, alias="hazmatCertNo")
hazmat_cert_expire: Optional[date] = Field(default=None, alias="hazmatCertExpire")
remark: Optional[str] = None
model_config = {"populate_by_name": True}
class DriverRead(DriverBase):
id: str
tenant_no: str = Field(alias="tenantNo")
order_num: Optional[int] = Field(default=None, alias="orderNum")
create_by: Optional[str] = Field(default=None, alias="createBy")
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
create_time: datetime = Field(alias="createTime")
update_by: Optional[str] = Field(default=None, alias="updateBy")
update_time: datetime = Field(alias="updateTime")
del_flag: int = Field(default=0, alias="delFlag")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 车辆-司机关联 Schema(兼容)
# =============================================================================
class VehicleDriverCreate(BaseModel):
vehicle_id: str = Field(..., alias="vehicleId", description="车辆ID")
driver_id: str = Field(..., alias="driverId", description="司机ID")
is_default: int = Field(default=0, alias="isDefault", description="是否默认 0-否 1-是")
model_config = {"populate_by_name": True}
class VehicleDriverRead(BaseModel):
id: str
vehicle_id: str = Field(alias="vehicleId")
driver_id: str = Field(alias="driverId")
is_default: int = Field(alias="isDefault")
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
model_config = {"from_attributes": True, "populate_by_name": True}
+106
View File
@@ -0,0 +1,106 @@
"""运输计划管理 - 运费结算 Schema"""
from datetime import date, datetime
from decimal import Decimal
from typing import Optional
from pydantic import BaseModel, Field
# =============================================================================
# 运费结算 Schema
# =============================================================================
class FreightSettlementBase(BaseModel):
total_freight: Decimal = Field(default=Decimal("0.00"), alias="totalFreight", description="运费合计")
invoice_amount: Optional[Decimal] = Field(default=None, alias="invoiceAmount", description="发票金额")
invoice_no: Optional[str] = Field(default=None, max_length=50, alias="invoiceNo", description="发票号")
invoice_date: Optional[date] = Field(default=None, alias="invoiceDate", description="开票日期")
settlement_status: str = Field(default="pending", alias="settlementStatus", description="结算状态")
remark: Optional[str] = None
class FreightSettlementCreate(BaseModel):
transport_ids: list[str] = Field(..., alias="transportIds", description="运输ID列表")
model_config = {"populate_by_name": True}
class FreightSettlementUpdate(BaseModel):
invoice_amount: Optional[Decimal] = Field(default=None, alias="invoiceAmount")
invoice_no: Optional[str] = Field(default=None, max_length=50, alias="invoiceNo")
invoice_date: Optional[date] = Field(default=None, alias="invoiceDate")
settlement_status: Optional[str] = Field(default=None, alias="settlementStatus")
remark: Optional[str] = None
model_config = {"populate_by_name": True}
class FreightSettlementRead(FreightSettlementBase):
id: str
settlement_no: str = Field(alias="settlementNo")
tenant_no: str = Field(alias="tenantNo")
order_num: Optional[int] = Field(default=None, alias="orderNum")
create_by: Optional[str] = Field(default=None, alias="createBy")
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
create_time: datetime = Field(alias="createTime")
update_by: Optional[str] = Field(default=None, alias="updateBy")
update_time: datetime = Field(alias="updateTime")
del_flag: int = Field(default=0, alias="delFlag")
model_config = {"from_attributes": True, "populate_by_name": True}
class FreightSettlementWithTransports(FreightSettlementRead):
transports: list = []
class FreightSettlementTransportRead(BaseModel):
id: str
settlement_id: str = Field(alias="settlementId")
transport_id: str = Field(alias="transportId")
freight_amount: Decimal = Field(alias="freightAmount")
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 汇款凭证 Schema
# =============================================================================
class RemittanceVoucherCreate(BaseModel):
settlement_id: str = Field(..., alias="settlementId", description="结算单ID")
remittance_date: Optional[date] = Field(default=None, alias="remittanceDate", description="汇款日期")
remittance_amount: Optional[Decimal] = Field(default=None, alias="remittanceAmount", description="汇款金额")
voucher_urls: Optional[list[str]] = Field(default=None, alias="voucherUrls", description="凭证文件URLs")
remark: Optional[str] = None
model_config = {"populate_by_name": True}
class RemittanceVoucherRead(BaseModel):
id: str
settlement_id: str = Field(alias="settlementId")
voucher_no: Optional[str] = Field(default=None, alias="voucherNo")
remittance_date: Optional[date] = Field(default=None, alias="remittanceDate")
remittance_amount: Optional[Decimal] = Field(default=None, alias="remittanceAmount")
voucher_urls: Optional[str] = Field(default=None, alias="voucherUrls")
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 列表查询
# =============================================================================
class FreightSettlementListQuery(BaseModel):
q: Optional[str] = Field(default=None, description="模糊搜索")
settlement_status: Optional[str] = Field(default=None, alias="settlementStatus", description="结算状态")
page: int = Field(default=1, ge=1)
page_size: int = Field(default=20, ge=1, le=100, alias="pageSize")
model_config = {"populate_by_name": True}
class FreightSettlementListResponse(BaseModel):
total: int
list: list[FreightSettlementRead]
+182
View File
@@ -0,0 +1,182 @@
"""运输计划管理 - 库存统计 Schema"""
from datetime import date, datetime
from decimal import Decimal
from typing import Optional
from pydantic import BaseModel, Field
# =============================================================================
# 库存台账 Schema
# =============================================================================
class InventoryRead(BaseModel):
id: str
product_id: str = Field(alias="productId")
product_no: str = Field(alias="productNo")
product_name: str = Field(alias="productName")
model: Optional[str] = None
unit: str
stock_qty: Decimal = Field(alias="stockQty")
stock_amount: Decimal = Field(alias="stockAmount")
low_stock_warning: Optional[Decimal] = Field(default=None, alias="lowStockWarning")
high_stock_warning: Optional[Decimal] = Field(default=None, alias="highStockWarning")
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
update_time: datetime = Field(alias="updateTime")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 库存流水 Schema
# =============================================================================
class InventoryTransactionRead(BaseModel):
id: str
product_id: str = Field(alias="productId")
product_name: str = Field(alias="productName")
transaction_type: str = Field(alias="transactionType")
plan_id: Optional[str] = Field(default=None, alias="planId")
plan_no: Optional[str] = Field(default=None, alias="planNo")
qty: Decimal
unit_price: Decimal = Field(alias="unitPrice")
amount: Decimal
stock_after: Decimal = Field(alias="stockAfter")
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 库存预警 Schema
# =============================================================================
class InventoryWarningRead(BaseModel):
id: str
product_id: str = Field(alias="productId")
product_name: str = Field(alias="productName")
warning_type: str = Field(alias="warningType")
current_qty: Decimal = Field(alias="currentQty")
threshold_value: Decimal = Field(alias="thresholdValue")
status: str
resolve_time: Optional[datetime] = Field(default=None, alias="resolveTime")
resolve_remark: Optional[str] = Field(default=None, alias="resolveRemark")
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
model_config = {"from_attributes": True, "populate_by_name": True}
class InventoryWarningUpdate(BaseModel):
status: str = Field(..., description="状态 pending/resolved")
resolve_remark: Optional[str] = Field(default=None, alias="resolveRemark", description="处理备注")
model_config = {"populate_by_name": True}
class InventoryWarningThreshold(BaseModel):
product_id: str = Field(..., alias="productId", description="产品ID")
low_stock_warning: Optional[Decimal] = Field(default=None, alias="lowStockWarning", description="最低库存预警值")
high_stock_warning: Optional[Decimal] = Field(default=None, alias="highStockWarning", description="最高库存预警值")
model_config = {"populate_by_name": True}
# =============================================================================
# 证件到期提醒 Schema
# =============================================================================
class DocumentReminderRead(BaseModel):
id: str
cert_id: Optional[str] = Field(default=None, alias="certId")
owner_type: Optional[str] = Field(default=None, alias="ownerType")
owner_id: Optional[str] = Field(default=None, alias="ownerId")
owner_label: Optional[str] = Field(default=None, alias="ownerLabel")
driver_id: Optional[str] = Field(default=None, alias="driverId")
driver_name: Optional[str] = Field(default=None, alias="driverName")
document_type: str = Field(alias="documentType")
document_no: Optional[str] = Field(default=None, alias="documentNo")
expire_date: date = Field(alias="expireDate")
days_remaining: int = Field(alias="daysRemaining")
status: str
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
model_config = {"from_attributes": True, "populate_by_name": True}
class DocumentReminderUpdate(BaseModel):
status: str = Field(..., description="状态 pending/resolved")
remark: Optional[str] = None
model_config = {"populate_by_name": True}
# =============================================================================
# 查询参数
# =============================================================================
class InventoryLedgerQuery(BaseModel):
product_name: Optional[str] = Field(default=None, alias="productName", description="产品名称")
page: int = Field(default=1, ge=1)
page_size: int = Field(default=20, ge=1, le=100, alias="pageSize")
model_config = {"populate_by_name": True}
class InventoryLedgerResponse(BaseModel):
total: int
list: list[InventoryRead]
class InventoryTransactionQuery(BaseModel):
product_id: Optional[str] = Field(default=None, alias="productId", description="产品ID")
transaction_type: Optional[str] = Field(default=None, alias="transactionType", description="事务类型 inbound/outbound")
date_from: Optional[date] = Field(default=None, alias="dateFrom", description="开始日期")
date_to: Optional[date] = Field(default=None, alias="dateTo", description="结束日期")
page: int = Field(default=1, ge=1)
page_size: int = Field(default=20, ge=1, le=100, alias="pageSize")
model_config = {"populate_by_name": True}
class InventoryTransactionResponse(BaseModel):
total: int
list: list[InventoryTransactionRead]
class InventorySummaryQuery(BaseModel):
group_by: str = Field(default="month", alias="groupBy", description="汇总维度 month/week")
date_from: date = Field(..., alias="dateFrom", description="开始日期")
date_to: date = Field(..., alias="dateTo", description="结束日期")
product_id: Optional[str] = Field(default=None, alias="productId", description="产品ID")
model_config = {"populate_by_name": True}
class InventorySummaryItem(BaseModel):
period: str
product_id: Optional[str] = Field(default=None, alias="productId")
product_name: str = Field(alias="productName")
inbound_qty: Decimal = Field(alias="inboundQty")
outbound_qty: Decimal = Field(alias="outboundQty")
net_change: Decimal = Field(alias="netChange")
class InventorySummaryResponse(BaseModel):
list: list[InventorySummaryItem]
class TransportStatsQuery(BaseModel):
group_by: str = Field(default="carrier", alias="groupBy", description="统计维度 carrier/vehicle")
date_from: Optional[date] = Field(default=None, alias="dateFrom", description="开始日期")
date_to: Optional[date] = Field(default=None, alias="dateTo", description="结束日期")
model_config = {"populate_by_name": True}
class TransportStatsItem(BaseModel):
group_key: str = Field(alias="groupKey")
group_name: str = Field(alias="groupName")
trip_count: int = Field(alias="tripCount")
total_freight: Decimal = Field(alias="totalFreight")
class TransportStatsResponse(BaseModel):
list: list[TransportStatsItem]
+253
View File
@@ -0,0 +1,253 @@
"""运输计划管理 - 计划 Schema"""
from datetime import date, datetime
from decimal import Decimal
from typing import Optional
from pydantic import BaseModel, Field
# =============================================================================
# 计划产品明细 Schema
# =============================================================================
class PlanProductBase(BaseModel):
product_id: str = Field(..., alias="productId", description="产品ID")
product_no: str = Field(..., max_length=50, alias="productNo", description="产品编号")
product_name: str = Field(..., max_length=200, alias="productName", description="产品名称")
model: Optional[str] = Field(default=None, max_length=100, description="规格型号")
unit: str = Field(default="吨", max_length=20, description="单位")
category_name: Optional[str] = Field(default=None, max_length=200, alias="categoryName", description="产品分类")
package_spec: Optional[str] = Field(default=None, max_length=200, alias="packageSpec", description="包装规格")
delivery_method: Optional[str] = Field(default=None, max_length=50, alias="deliveryMethod", description="送货方式")
quantity: Optional[Decimal] = Field(default=None, description="合同数量")
actual_qty: Optional[Decimal] = Field(default=None, alias="actualQty", description="实际数量")
tax_price: Optional[Decimal] = Field(default=None, alias="taxPrice", description="含税单价")
tax_amount: Optional[Decimal] = Field(default=None, alias="taxAmount", description="税费")
tax_subtotal: Optional[Decimal] = Field(default=None, alias="taxSubtotal", description="含税总价")
is_explosive: int = Field(default=0, alias="isExplosive", description="是否易制爆")
is_toxic: int = Field(default=0, alias="isToxic", description="是否易制毒")
purchase_cert_url: Optional[str] = Field(default=None, alias="purchaseCertUrl", description="购买证URL")
transport_cert_url: Optional[str] = Field(default=None, alias="transportCertUrl", description="运输证URL")
inbound_estimate_qty: Optional[Decimal] = Field(default=None, alias="inboundEstimateQty", description="入库预估数")
inbound_qty: Optional[Decimal] = Field(default=None, alias="inboundQty", description="入库数")
inbound_price: Optional[Decimal] = Field(default=None, alias="inboundPrice", description="入库价")
inbound_amount: Optional[Decimal] = Field(default=None, alias="inboundAmount", description="入库金额")
outbound_estimate_qty: Optional[Decimal] = Field(default=None, alias="outboundEstimateQty", description="出库预估数")
outbound_qty: Optional[Decimal] = Field(default=None, alias="outboundQty", description="出库数")
outbound_price: Optional[Decimal] = Field(default=None, alias="outboundPrice", description="出库单价")
outbound_amount: Optional[Decimal] = Field(default=None, alias="outboundAmount", description="出库金额")
remark: Optional[str] = Field(default=None, max_length=512, description="备注")
class PlanProductCreate(PlanProductBase):
model_config = {"populate_by_name": True}
class PlanProductUpdate(BaseModel):
product_id: Optional[str] = Field(default=None, alias="productId")
product_no: Optional[str] = Field(default=None, max_length=50, alias="productNo")
product_name: Optional[str] = Field(default=None, max_length=200, alias="productName")
model: Optional[str] = Field(default=None, max_length=100)
unit: Optional[str] = Field(default=None, max_length=20)
is_explosive: Optional[int] = Field(default=None, alias="isExplosive")
is_toxic: Optional[int] = Field(default=None, alias="isToxic")
purchase_cert_url: Optional[str] = Field(default=None, alias="purchaseCertUrl")
transport_cert_url: Optional[str] = Field(default=None, alias="transportCertUrl")
inbound_estimate_qty: Optional[Decimal] = Field(default=None, alias="inboundEstimateQty")
inbound_qty: Optional[Decimal] = Field(default=None, alias="inboundQty")
inbound_price: Optional[Decimal] = Field(default=None, alias="inboundPrice")
inbound_amount: Optional[Decimal] = Field(default=None, alias="inboundAmount")
outbound_estimate_qty: Optional[Decimal] = Field(default=None, alias="outboundEstimateQty")
outbound_qty: Optional[Decimal] = Field(default=None, alias="outboundQty")
outbound_price: Optional[Decimal] = Field(default=None, alias="outboundPrice")
outbound_amount: Optional[Decimal] = Field(default=None, alias="outboundAmount")
model_config = {"populate_by_name": True}
class PlanProductRead(PlanProductBase):
id: str
plan_id: str = Field(alias="planId")
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
update_time: datetime = Field(alias="updateTime")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 计划主表 Schema
# =============================================================================
class PlanBase(BaseModel):
belongs_company: str = Field(..., alias="belongsCompany", description="归属公司 shanxia-安庆山峡 yundong-安徽云栋")
plan_type: str = Field(..., alias="planType", description="单据类型 direct-直销单 inbound-入库单 outbound-出库单")
follow_status: str = Field(default="draft", alias="followStatus", description="跟进状态")
transport_status: str = Field(default="pending", alias="transportStatus", description="运输安排状态")
archive_status: str = Field(default="unarchived", alias="archiveStatus", description="归档状态")
complete_status: str = Field(default="no", alias="completeStatus", description="完成状态")
contract_id: Optional[str] = Field(default=None, alias="contractId", description="CRM合同ID")
contract_no: Optional[str] = Field(default=None, max_length=50, alias="contractNo", description="合同编号")
supplier_id: Optional[str] = Field(default=None, alias="supplierId", description="供应商ID")
supplier_name: Optional[str] = Field(default=None, max_length=200, alias="supplierName", description="供应商名称")
destination_id: Optional[str] = Field(default=None, alias="destinationId", description="目的地ID")
destination_name: Optional[str] = Field(default=None, max_length=200, alias="destinationName", description="目的地名称")
customer_id: Optional[str] = Field(default=None, alias="customerId", description="客户ID")
customer_name: Optional[str] = Field(default=None, max_length=200, alias="customerName", description="客户名称")
contact_name: Optional[str] = Field(default=None, max_length=100, alias="contactName", description="联系人")
contact_phone: Optional[str] = Field(default=None, max_length=32, alias="contactPhone", description="联系电话")
party_a: Optional[str] = Field(default=None, max_length=200, alias="partyA", description="甲方")
party_b: Optional[str] = Field(default=None, max_length=200, alias="partyB", description="乙方")
contract_start_date: Optional[date] = Field(default=None, alias="contractStartDate", description="合同开始日期")
contract_end_date: Optional[date] = Field(default=None, alias="contractEndDate", description="合同结束日期")
delivery_method: Optional[str] = Field(default=None, alias="deliveryMethod", description="送货方式")
settlement_method: Optional[str] = Field(default=None, max_length=50, alias="settlementMethod", description="结算方式")
has_freight: int = Field(default=0, alias="hasFreight", description="是否有运输费用")
pickup_address: Optional[str] = Field(default=None, max_length=500, alias="pickupAddress", description="取货地址")
pickup_time: Optional[datetime] = Field(default=None, alias="pickupTime", description="取货时间")
pickup_notes: Optional[str] = Field(default=None, max_length=500, alias="pickupNotes", description="取货注意事项")
destination_address: Optional[str] = Field(default=None, max_length=500, alias="destinationAddress", description="目的地地址")
delivery_time: Optional[datetime] = Field(default=None, alias="deliveryTime", description="送达时间")
destination_notes: Optional[str] = Field(default=None, max_length=500, alias="destinationNotes", description="目的地注意事项")
notify_message: Optional[str] = Field(default=None, alias="notifyMessage", description="通知信息")
follow_user_id: Optional[str] = Field(default=None, alias="followUserId", description="跟进人ID")
follow_user_name: Optional[str] = Field(default=None, max_length=100, alias="followUserName", description="跟进人姓名")
remark: Optional[str] = None
class PlanCreate(PlanBase):
plan_date: date = Field(..., alias="planDate", description="计划日期")
products: Optional[list[PlanProductCreate]] = Field(default=None, description="产品明细列表")
model_config = {"populate_by_name": True}
class PlanTransportCreateBlock(BaseModel):
vehicle_id: str = Field(..., alias="vehicleId", description="车辆ID")
driver_id: Optional[str] = Field(default=None, alias="driverId", description="司机/人员ID")
carrier_id: Optional[str] = Field(default=None, alias="carrierId", description="承运商ID")
distance_km: Optional[Decimal] = Field(default=None, alias="distanceKm", description="运输公里数")
freight_type: str = Field(default="by_weight", alias="freightType", description="运费计算方式")
transport_qty: Optional[Decimal] = Field(default=None, alias="transportQty", description="运输量")
freight_price: Optional[Decimal] = Field(default=None, alias="freightPrice", description="运输单价")
freight_amount: Optional[Decimal] = Field(default=None, alias="freightAmount", description="运费金额")
has_invoice: int = Field(default=0, alias="hasInvoice", description="是否开票")
remark: Optional[str] = None
model_config = {"populate_by_name": True}
class PlanUpdate(BaseModel):
plan_date: Optional[date] = Field(default=None, alias="planDate")
belongs_company: Optional[str] = Field(default=None, alias="belongsCompany")
plan_type: Optional[str] = Field(default=None, alias="planType")
follow_status: Optional[str] = Field(default=None, alias="followStatus")
transport_status: Optional[str] = Field(default=None, alias="transportStatus")
supplier_id: Optional[str] = Field(default=None, alias="supplierId")
supplier_name: Optional[str] = Field(default=None, max_length=200, alias="supplierName")
destination_id: Optional[str] = Field(default=None, alias="destinationId")
destination_name: Optional[str] = Field(default=None, max_length=200, alias="destinationName")
customer_id: Optional[str] = Field(default=None, alias="customerId")
customer_name: Optional[str] = Field(default=None, max_length=200, alias="customerName")
contact_name: Optional[str] = Field(default=None, max_length=100, alias="contactName")
contact_phone: Optional[str] = Field(default=None, max_length=32, alias="contactPhone")
party_a: Optional[str] = Field(default=None, max_length=200, alias="partyA")
party_b: Optional[str] = Field(default=None, max_length=200, alias="partyB")
contract_start_date: Optional[date] = Field(default=None, alias="contractStartDate")
contract_end_date: Optional[date] = Field(default=None, alias="contractEndDate")
delivery_method: Optional[str] = Field(default=None, alias="deliveryMethod")
settlement_method: Optional[str] = Field(default=None, max_length=50, alias="settlementMethod")
has_freight: Optional[int] = Field(default=None, alias="hasFreight")
pickup_address: Optional[str] = Field(default=None, max_length=500, alias="pickupAddress")
pickup_time: Optional[datetime] = Field(default=None, alias="pickupTime")
pickup_notes: Optional[str] = Field(default=None, max_length=500, alias="pickupNotes")
destination_address: Optional[str] = Field(default=None, max_length=500, alias="destinationAddress")
delivery_time: Optional[datetime] = Field(default=None, alias="deliveryTime")
destination_notes: Optional[str] = Field(default=None, max_length=500, alias="destinationNotes")
notify_message: Optional[str] = Field(default=None, alias="notifyMessage")
follow_user_id: Optional[str] = Field(default=None, alias="followUserId")
follow_user_name: Optional[str] = Field(default=None, alias="followUserName")
remark: Optional[str] = None
products: Optional[list[PlanProductCreate]] = None
transport: Optional[PlanTransportCreateBlock] = Field(default=None, description="运输预选/更新(有车牌时同步车辆与运费)")
model_config = {"populate_by_name": True}
class PlanRead(PlanBase):
id: str
plan_no: str = Field(alias="planNo")
plan_date: date = Field(alias="planDate")
vehicle_id: Optional[str] = Field(default=None, alias="vehicleId")
license_plate: Optional[str] = Field(default=None, alias="licensePlate")
driver_id: Optional[str] = Field(default=None, alias="driverId")
driver_name: Optional[str] = Field(default=None, alias="driverName")
transport_id: Optional[str] = Field(default=None, alias="transportId")
transport_no: Optional[str] = Field(default=None, alias="transportNo")
total_amount: Decimal = Field(alias="totalAmount")
freight_amount: Decimal = Field(alias="freightAmount")
tenant_no: str = Field(alias="tenantNo")
order_num: Optional[int] = Field(default=None, alias="orderNum")
create_by: Optional[str] = Field(default=None, alias="createBy")
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
create_time: datetime = Field(alias="createTime")
update_by: Optional[str] = Field(default=None, alias="updateBy")
update_time: datetime = Field(alias="updateTime")
del_flag: int = Field(default=0, alias="delFlag")
model_config = {"from_attributes": True, "populate_by_name": True}
class PlanWithProducts(PlanRead):
products: list[PlanProductRead] = []
# =============================================================================
# 从合同创建计划
# =============================================================================
class CreateFromContractRequest(BaseModel):
contract_id: str = Field(..., alias="contractId", description="CRM合同ID")
plan_date: date = Field(..., alias="planDate", description="计划日期")
follow_user_id: Optional[str] = Field(default=None, alias="followUserId", description="跟进人ID")
follow_user_name: Optional[str] = Field(default=None, max_length=100, alias="followUserName", description="跟进人姓名")
model_config = {"populate_by_name": True}
class PlanCreateFull(PlanCreate):
contract_id: str = Field(..., alias="contractId", description="CRM合同ID")
transport: Optional[PlanTransportCreateBlock] = Field(default=None, description="运输安排(有车牌时创建运输)")
model_config = {"populate_by_name": True}
# =============================================================================
# 计划列表查询
# =============================================================================
class PlanListQuery(BaseModel):
q: Optional[str] = Field(default=None, description="模糊搜索计划号/客户名称")
plan_no: Optional[str] = Field(default=None, alias="planNo", description="计划编号")
plan_type: Optional[str] = Field(default=None, alias="planType", description="单据类型")
follow_status: Optional[str] = Field(default=None, alias="followStatus", description="跟进状态")
transport_status: Optional[str] = Field(default=None, alias="transportStatus", description="运输状态")
archive_status: Optional[str] = Field(default=None, alias="archiveStatus", description="归档状态")
customer_name: Optional[str] = Field(default=None, alias="customerName", description="客户名称")
plan_date_from: Optional[date] = Field(default=None, alias="planDateFrom", description="计划日期开始")
plan_date_to: Optional[date] = Field(default=None, alias="planDateTo", description="计划日期结束")
page: int = Field(default=1, ge=1, description="页码")
page_size: int = Field(default=20, ge=1, le=100, alias="pageSize", description="每页数量")
model_config = {"populate_by_name": True}
class PlanProductCertItem(BaseModel):
id: str = Field(..., description="计划产品明细ID")
purchase_cert_url: Optional[str] = Field(default=None, alias="purchaseCertUrl", description="购买证URL")
transport_cert_url: Optional[str] = Field(default=None, alias="transportCertUrl", description="运输证URL")
model_config = {"populate_by_name": True}
class PlanProductCertsUpdate(BaseModel):
products: list[PlanProductCertItem] = Field(..., description="危化品证书更新列表")
model_config = {"populate_by_name": True}
class PlanListResponse(BaseModel):
total: int
list: list[PlanWithProducts]
+231
View File
@@ -0,0 +1,231 @@
"""运输计划管理 - 运输 Schema"""
from datetime import date, datetime
from decimal import Decimal
from typing import Optional
from pydantic import BaseModel, Field
# =============================================================================
# 运输 Schema
# =============================================================================
class TransportBase(BaseModel):
vehicle_id: Optional[str] = Field(default=None, alias="vehicleId", description="车辆ID")
license_plate: Optional[str] = Field(default=None, max_length=20, alias="licensePlate", description="车牌号")
driver_id: Optional[str] = Field(default=None, alias="driverId", description="司机ID")
driver_name: Optional[str] = Field(default=None, max_length=100, alias="driverName", description="司机姓名")
driver_phone: Optional[str] = Field(default=None, max_length=32, alias="driverPhone", description="司机电话")
carrier_id: Optional[str] = Field(default=None, alias="carrierId", description="承运商ID")
carrier_name: Optional[str] = Field(default=None, max_length=200, alias="carrierName", description="承运商名称")
transport_medium: Optional[str] = Field(default=None, max_length=100, alias="transportMedium", description="运输介质")
start_point: Optional[str] = Field(default=None, max_length=200, alias="startPoint", description="运输起点")
end_point: Optional[str] = Field(default=None, max_length=200, alias="endPoint", description="运输终点")
distance_km: Optional[Decimal] = Field(default=None, alias="distanceKm", description="运输公里数")
unit: Optional[str] = Field(default=None, max_length=20, description="计量单位")
transport_qty: Optional[Decimal] = Field(default=None, alias="transportQty", description="运输量")
freight_price: Optional[Decimal] = Field(default=None, alias="freightPrice", description="运输单价")
freight_amount: Decimal = Field(default=Decimal("0.00"), alias="freightAmount", description="运输费用")
freight_type: str = Field(default="by_weight", alias="freightType", description="运费计算方式")
has_invoice: int = Field(default=0, alias="hasInvoice", description="是否开票")
qr_expire_date: Optional[date] = Field(default=None, alias="qrExpireDate", description="二维码有效期")
transport_status: str = Field(default="draft", alias="transportStatus", description="运输状态")
approval_status: str = Field(default="none", alias="approvalStatus", description="审批状态")
remark: Optional[str] = None
class TransportCreate(TransportBase):
plan_ids: Optional[list[str]] = Field(default=None, alias="planIds", description="关联计划ID列表")
model_config = {"populate_by_name": True}
class TransportArrange(BaseModel):
vehicle_id: str = Field(..., alias="vehicleId", description="车辆ID")
driver_id: str = Field(..., alias="driverId", description="司机ID")
carrier_id: Optional[str] = Field(default=None, alias="carrierId", description="承运商ID")
transport_medium: Optional[str] = Field(default=None, alias="transportMedium", description="运输介质")
start_point: Optional[str] = Field(default=None, alias="startPoint", description="运输起点")
end_point: Optional[str] = Field(default=None, alias="endPoint", description="运输终点")
distance_km: Optional[Decimal] = Field(default=None, alias="distanceKm", description="运输公里数")
unit: Optional[str] = Field(default=None, description="计量单位")
freight_type: str = Field(default="by_weight", alias="freightType", description="运费计算方式 by_weight/by_trip")
freight_price: Optional[Decimal] = Field(default=None, alias="freightPrice", description="运输单价")
freight_amount: Optional[Decimal] = Field(default=None, alias="freightAmount", description="运费金额")
has_invoice: int = Field(default=0, alias="hasInvoice", description="是否开票")
remark: Optional[str] = None
generate_dibang_plan: bool = Field(default=False, alias="generateDibangPlan", description="是否生成地磅计划")
model_config = {"populate_by_name": True}
class TransportInventoryLinkRead(BaseModel):
plan_product_id: str = Field(alias="planProductId")
product_name: str = Field(alias="productName")
db_purchase_plan_id: str = Field(alias="dbPurchasePlanId")
db_inventory_id: str = Field(alias="dbInventoryId")
batch_no: str = Field(alias="batchNo")
plan_no: str = Field(alias="planNo")
model_config = {"populate_by_name": True}
class TransportUpdate(BaseModel):
vehicle_id: Optional[str] = Field(default=None, alias="vehicleId")
license_plate: Optional[str] = Field(default=None, max_length=20, alias="licensePlate")
driver_id: Optional[str] = Field(default=None, alias="driverId")
driver_name: Optional[str] = Field(default=None, max_length=100, alias="driverName")
driver_phone: Optional[str] = Field(default=None, max_length=32, alias="driverPhone")
carrier_id: Optional[str] = Field(default=None, alias="carrierId")
carrier_name: Optional[str] = Field(default=None, max_length=200, alias="carrierName")
transport_medium: Optional[str] = Field(default=None, max_length=100, alias="transportMedium")
start_point: Optional[str] = Field(default=None, max_length=200, alias="startPoint")
end_point: Optional[str] = Field(default=None, max_length=200, alias="endPoint")
distance_km: Optional[Decimal] = Field(default=None, alias="distanceKm")
unit: Optional[str] = Field(default=None, max_length=20)
freight_price: Optional[Decimal] = Field(default=None, alias="freightPrice")
freight_amount: Optional[Decimal] = Field(default=None, alias="freightAmount")
freight_type: Optional[str] = Field(default=None, alias="freightType")
has_invoice: Optional[int] = Field(default=None, alias="hasInvoice")
qr_expire_date: Optional[date] = Field(default=None, alias="qrExpireDate")
transport_status: Optional[str] = Field(default=None, alias="transportStatus")
approval_status: Optional[str] = Field(default=None, alias="approvalStatus")
remark: Optional[str] = None
model_config = {"populate_by_name": True}
class TransportRead(TransportBase):
id: str
transport_no: str = Field(alias="transportNo")
qr_code: Optional[str] = Field(default=None, alias="qrCode")
feedback_time: Optional[datetime] = Field(default=None, alias="feedbackTime")
feedback_qty: Optional[Decimal] = Field(default=None, alias="feedbackQty")
feedback_images: Optional[str] = Field(default=None, alias="feedbackImages")
feedback_remark: Optional[str] = Field(default=None, alias="feedbackRemark")
tenant_no: str = Field(alias="tenantNo")
order_num: Optional[int] = Field(default=None, alias="orderNum")
create_by: Optional[str] = Field(default=None, alias="createBy")
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
create_time: datetime = Field(alias="createTime")
update_by: Optional[str] = Field(default=None, alias="updateBy")
update_time: datetime = Field(alias="updateTime")
del_flag: int = Field(default=0, alias="delFlag")
model_config = {"from_attributes": True, "populate_by_name": True}
class TransportArrangeResult(TransportRead):
driver_access_token: Optional[str] = Field(default=None, alias="driverAccessToken")
driver_url: Optional[str] = Field(default=None, alias="driverUrl")
inventory_records: list[TransportInventoryLinkRead] = Field(
default_factory=list, alias="inventoryRecords"
)
model_config = {"from_attributes": True, "populate_by_name": True}
class PlanArrangeInfoRead(BaseModel):
driver_url: Optional[str] = Field(default=None, alias="driverUrl")
license_plate: Optional[str] = Field(default=None, alias="licensePlate")
inventory_records: list[TransportInventoryLinkRead] = Field(
default_factory=list, alias="inventoryRecords"
)
model_config = {"populate_by_name": True}
class TransportWithPlans(TransportRead):
plan_ids: list[str] = Field(default_factory=list, alias="planIds")
# =============================================================================
# 司机扫码回传
# =============================================================================
class TransportFeedback(BaseModel):
transport_no: str = Field(..., alias="transportNo", description="运输编号")
verify_code: Optional[str] = Field(default=None, alias="verifyCode", description="验证码")
feedback_qty: Optional[Decimal] = Field(default=None, alias="feedbackQty", description="回传数量")
feedback_images: Optional[list[str]] = Field(default=None, alias="feedbackImages", description="回传图片URLs")
feedback_remark: Optional[str] = Field(default=None, alias="feedbackRemark", description="回传备注")
model_config = {"populate_by_name": True}
class PublicTransportFeedback(BaseModel):
feedback_images: Optional[list[str]] = Field(default=None, alias="feedbackImages")
feedback_remark: Optional[str] = Field(default=None, alias="feedbackRemark")
model_config = {"populate_by_name": True}
class PublicTransportPlanProductRead(BaseModel):
product_name: str = Field(alias="productName")
model: Optional[str] = None
package_spec: Optional[str] = Field(default=None, alias="packageSpec")
unit: Optional[str] = None
quantity: Optional[Decimal] = None
model_config = {"populate_by_name": True}
class PublicTransportPageRead(BaseModel):
plan_no: str = Field(alias="planNo")
plan_date: Optional[str] = Field(default=None, alias="planDate")
plan_type: str = Field(alias="planType")
pickup_address: Optional[str] = Field(default=None, alias="pickupAddress")
destination_address: Optional[str] = Field(default=None, alias="destinationAddress")
license_plate: Optional[str] = Field(default=None, alias="licensePlate")
driver_name: Optional[str] = Field(default=None, alias="driverName")
driver_phone: Optional[str] = Field(default=None, alias="driverPhone")
products: list[PublicTransportPlanProductRead] = Field(default_factory=list)
feedback_remark: Optional[str] = Field(default=None, alias="feedbackRemark")
feedback_images: list[str] = Field(default_factory=list, alias="feedbackImages")
feedback_time: Optional[datetime] = Field(default=None, alias="feedbackTime")
plan_voided: bool = Field(default=False, alias="planVoided")
model_config = {"populate_by_name": True}
# =============================================================================
# 审批
# =============================================================================
class ApprovalSubmit(BaseModel):
approver_ids: list[str] = Field(..., alias="approverIds", description="审批人ID列表(按顺序)")
model_config = {"populate_by_name": True}
class ApprovalRequest(BaseModel):
action: str = Field(..., description="审批动作 approve/reject")
comment: Optional[str] = Field(default=None, description="审批意见")
model_config = {"populate_by_name": True}
class ApprovalRecordRead(BaseModel):
id: str
transport_id: str = Field(alias="transportId")
approver_id: str = Field(alias="approverId")
approver_name: str = Field(alias="approverName")
approval_order: int = Field(alias="approvalOrder")
status: str
comment: Optional[str] = None
approval_time: Optional[datetime] = Field(default=None, alias="approvalTime")
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 列表查询
# =============================================================================
class TransportListQuery(BaseModel):
q: Optional[str] = Field(default=None, description="模糊搜索")
transport_no: Optional[str] = Field(default=None, alias="transportNo", description="运输编号")
transport_status: Optional[str] = Field(default=None, alias="transportStatus", description="运输状态")
approval_status: Optional[str] = Field(default=None, alias="approvalStatus", description="审批状态")
vehicle_id: Optional[str] = Field(default=None, alias="vehicleId", description="车辆ID")
driver_id: Optional[str] = Field(default=None, alias="driverId", description="司机ID")
page: int = Field(default=1, ge=1)
page_size: int = Field(default=20, ge=1, le=100, alias="pageSize")
model_config = {"populate_by_name": True}
class TransportListResponse(BaseModel):
total: int
list: list[TransportRead]
+69 -17
View File
@@ -5,6 +5,7 @@ from decimal import Decimal
from typing import Any, Dict, List, Optional, Sequence, Tuple
from sqlalchemy import and_, func, or_
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from app.core.bx_auth import BxUserContext
@@ -22,7 +23,14 @@ from app.schemas.bx.reimburse import ReimburseApplyOut, ReimburseDetailOut
from app.services.bx.approval_cycle import filter_current_cycle_approvals
from app.services.bx.attachment import AttachmentService
from app.services.bx.base import BxCrudService
from app.utils.bx_codegen import generate_apply_code, generate_title
from app.utils.bx_codegen import (
allocate_reimburse_title_seq,
generate_apply_code,
format_reimburse_title,
is_auto_reimburse_title,
parse_reimburse_date,
resolve_reimburse_title,
)
from app.utils.bx_date_range import current_month_bounds, parse_create_time_day_bounds
_REIMBURSE_MY_STATS_PASSED_STATUSES = ("approved", "processed", "paid", "offset")
@@ -374,24 +382,42 @@ class ReimburseService:
tenant_no = ReimburseService._tenant_no(db, user)
data = dict(obj_in)
total_amount = sum(float(d.get("amount", 0) or 0) for d in details)
title = data.pop("title", None) or generate_title(db, user.name, tenant_no)
reimburse_date = parse_reimburse_date(data.pop("reimburse_date", None))
requested_title = data.pop("title", None)
first_detail = details[0] if details else {}
apply_obj = BxReimburseApply(
id=generate_uuid(),
title=title,
amount=total_amount,
expense_id=str(first_detail.get("expense_id") or ""),
expense_name=first_detail.get("expense_name") or "",
applicant_id=user.id,
applicant_name=user.name,
tenant_no=tenant_no,
create_by=user.id,
create_dept_id=user.dept_id or "",
**data,
)
db.add(apply_obj)
db.flush()
apply_obj: BxReimburseApply | None = None
for attempt in range(5):
title, title_seq = resolve_reimburse_title(
db, user.name, tenant_no, reimburse_date, requested_title
)
apply_obj = BxReimburseApply(
id=generate_uuid(),
title=title,
reimburse_date=reimburse_date,
title_seq=title_seq,
amount=total_amount,
expense_id=str(first_detail.get("expense_id") or ""),
expense_name=first_detail.get("expense_name") or "",
applicant_id=user.id,
applicant_name=user.name,
tenant_no=tenant_no,
create_by=user.id,
create_dept_id=user.dept_id or "",
**data,
)
db.add(apply_obj)
try:
db.flush()
break
except IntegrityError:
db.rollback()
if attempt >= 4:
raise
continue
if apply_obj is None:
raise RuntimeError("报销申请创建失败")
for d in details:
detail = BxReimburseDetail(
@@ -423,9 +449,35 @@ class ReimburseService:
if not apply_obj:
return None
reimburse_date = None
date_changed = False
if "reimburse_date" in obj_in:
reimburse_date = parse_reimburse_date(obj_in.pop("reimburse_date"))
date_changed = reimburse_date != apply_obj.reimburse_date
requested_title = obj_in.pop("title", None)
for key, value in obj_in.items():
setattr(apply_obj, key, value)
if reimburse_date is not None:
apply_obj.reimburse_date = reimburse_date
if requested_title is not None:
apply_obj.title = str(requested_title).strip()
should_regen_title = date_changed and is_auto_reimburse_title(apply_obj.title)
if should_regen_title:
seq = allocate_reimburse_title_seq(
db, tenant_no, apply_obj.reimburse_date, exclude_apply_id=apply_id
)
apply_obj.title_seq = seq
apply_obj.title = format_reimburse_title(
apply_obj.applicant_name, apply_obj.reimburse_date, seq
)
elif requested_title is not None and not is_auto_reimburse_title(apply_obj.title):
apply_obj.title_seq = None
if details is not None:
db.query(BxReimburseDetail).filter(
BxReimburseDetail.reimburse_id == apply_id,
+211
View File
@@ -0,0 +1,211 @@
"""运输计划 - 证书 CRUD 与到期扫描"""
from __future__ import annotations
from datetime import date
from typing import Optional
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.models.pl_models import PlCert, PlDocumentReminder, PlPersonnel, PlVehicle
from app.schemas.pl.base_data import CertRead, CertRow
def list_owner_certs(
db: Session, tenant_no: str, owner_type: str, owner_id: str
) -> list[PlCert]:
return (
db.query(PlCert)
.filter(
PlCert.tenant_no == tenant_no,
PlCert.owner_type == owner_type,
PlCert.owner_id == owner_id,
PlCert.del_flag == 0,
)
.order_by(PlCert.order_num.asc(), PlCert.create_time.asc())
.all()
)
def certs_to_read(certs: list[PlCert]) -> list[CertRead]:
return [
CertRead(
id=c.id,
cert_id=c.id,
cert_name=c.cert_name,
cert_no=c.cert_no,
expire_date=c.expire_date,
remind_days=c.remind_days,
attachment_urls=c.attachment_urls,
owner_type=c.owner_type,
owner_id=c.owner_id,
status=c.status,
tenant_no=c.tenant_no,
create_time=c.create_time,
update_time=c.update_time,
)
for c in certs
]
def _normalize_cert_row(row: CertRow | dict) -> CertRow:
if isinstance(row, CertRow):
return row
return CertRow.model_validate(row)
def save_owner_certs(
db: Session,
owner_type: str,
owner_id: str,
cert_rows: list[CertRow | dict],
tenant_no: str,
*,
user_id: str,
dept_id: str,
) -> None:
"""按 cert_id upsert;未出现在列表中的旧证软删。"""
existing = list_owner_certs(db, tenant_no, owner_type, owner_id)
existing_map = {c.id: c for c in existing}
keep_ids: set[str] = set()
for idx, row in enumerate(cert_rows):
row = _normalize_cert_row(row)
cert_id = row.cert_id
if cert_id and cert_id in existing_map:
cert = existing_map[cert_id]
cert.cert_name = row.cert_name
cert.cert_no = row.cert_no
cert.expire_date = row.expire_date
cert.remind_days = row.remind_days
cert.attachment_urls = row.attachment_urls
cert.order_num = idx
cert.update_by = user_id
keep_ids.add(cert.id)
else:
cert = PlCert(
id=generate_uuid(),
tenant_no=tenant_no,
owner_type=owner_type,
owner_id=owner_id,
cert_name=row.cert_name,
cert_no=row.cert_no,
expire_date=row.expire_date,
remind_days=row.remind_days,
attachment_urls=row.attachment_urls,
status="valid",
order_num=idx,
create_by=user_id,
create_dept_id=dept_id,
)
db.add(cert)
db.flush()
keep_ids.add(cert.id)
for cert in existing:
if cert.id not in keep_ids:
cert.del_flag = 1
cert.update_by = user_id
def nearest_expire_date(
db: Session, tenant_no: str, owner_type: str, owner_id: str
) -> Optional[date]:
row = (
db.query(PlCert.expire_date)
.filter(
PlCert.tenant_no == tenant_no,
PlCert.owner_type == owner_type,
PlCert.owner_id == owner_id,
PlCert.del_flag == 0,
PlCert.expire_date.isnot(None),
)
.order_by(PlCert.expire_date.asc())
.first()
)
return row[0] if row else None
def _resolve_owner_label(
db: Session, tenant_no: str, owner_type: str, owner_id: str
) -> str:
if owner_type == "vehicle":
vehicle = (
db.query(PlVehicle)
.filter(
PlVehicle.id == owner_id,
PlVehicle.tenant_no == tenant_no,
PlVehicle.del_flag == 0,
)
.first()
)
return vehicle.license_plate if vehicle else owner_id
personnel = (
db.query(PlPersonnel)
.filter(
PlPersonnel.id == owner_id,
PlPersonnel.tenant_no == tenant_no,
PlPersonnel.del_flag == 0,
)
.first()
)
return personnel.personnel_name if personnel else owner_id
def scan_cert_expiry(db: Session, tenant_no: Optional[str] = None) -> int:
"""扫描 pl_cert 生成到期提醒,返回新建条数。"""
today = date.today()
query = db.query(PlCert).filter(
PlCert.del_flag == 0,
PlCert.expire_date.isnot(None),
PlCert.status == "valid",
)
if tenant_no:
query = query.filter(PlCert.tenant_no == tenant_no)
created_count = 0
for cert in query.all():
days_remaining = (cert.expire_date - today).days
if days_remaining < 0 or days_remaining > cert.remind_days:
continue
existing = (
db.query(PlDocumentReminder)
.filter(
PlDocumentReminder.cert_id == cert.id,
PlDocumentReminder.status == "pending",
PlDocumentReminder.del_flag == 0,
)
.first()
)
if existing:
continue
owner_label = _resolve_owner_label(
db, cert.tenant_no, cert.owner_type, cert.owner_id
)
driver_id = cert.owner_id if cert.owner_type == "personnel" else None
driver_name = owner_label if cert.owner_type == "personnel" else None
reminder = PlDocumentReminder(
id=generate_uuid(),
tenant_no=cert.tenant_no,
cert_id=cert.id,
owner_type=cert.owner_type,
owner_id=cert.owner_id,
owner_label=owner_label,
driver_id=driver_id,
driver_name=driver_name,
document_type=cert.cert_name,
document_no=cert.cert_no,
expire_date=cert.expire_date,
days_remaining=days_remaining,
status="pending",
create_by="system",
create_dept_id="",
)
db.add(reminder)
created_count += 1
return created_count
@@ -0,0 +1,415 @@
"""运输计划安排时联动地磅计划与出入库单。"""
from __future__ import annotations
import calendar
import re
from dataclasses import dataclass
from datetime import date, datetime
from decimal import Decimal
from typing import Optional
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.models.db_models import DbInboundOutbound, DbPurchasePlan, DbVehicle, DbWeighingSlip
from app.models.pl_models import PlPlan, PlPlanProduct, PlTransport, PlTransportDbLink
from app.services.db.inventory_id import next_inbound_outbound_id
from app.services.db.mappers import parse_date_str
from app.services.db.plan_helpers import default_execution_status, generate_plan_no
from app.services.db.product_helpers import (
apply_product_snapshot_to_inventory,
apply_product_snapshot_to_plan,
resolve_crm_product,
)
@dataclass
class DibangInventoryLinkResult:
plan_product_id: str
product_name: str
db_purchase_plan_id: str
db_inventory_id: str
batch_no: str
plan_no: str
def resolve_partner_company(plan: PlPlan, plan_type: str) -> str:
if plan_type == "inbound":
return (plan.supplier_name or plan.party_a or "").strip()
if plan_type == "outbound":
return (plan.customer_name or plan.party_b or "").strip()
return ""
def _month_range(plan_date: date) -> tuple[date, date]:
month_start = plan_date.replace(day=1)
last_day = calendar.monthrange(plan_date.year, plan_date.month)[1]
month_end = plan_date.replace(day=last_day)
return month_start, month_end
def _plan_type_to_business_type(plan_type: str) -> Optional[str]:
if plan_type == "inbound":
return "入库"
if plan_type == "outbound":
return "出库"
return None
def _product_quantity(product: PlPlanProduct) -> float:
for value in (product.quantity, product.inbound_estimate_qty, product.outbound_estimate_qty):
if value is not None:
return float(value)
return 0.0
def _generate_batch_no(db: Session, tenant_no: str) -> str:
rows = (
db.query(DbInboundOutbound.batch_no)
.filter(
DbInboundOutbound.tenant_no == tenant_no,
DbInboundOutbound.del_flag == 0,
DbInboundOutbound.batch_no.like("CRKDH%"),
)
.all()
)
max_seq = 0
pattern = re.compile(r"^CRKDH(\d+)$")
for (batch_no,) in rows:
if batch_no:
match = pattern.match(batch_no)
if match:
max_seq = max(max_seq, int(match.group(1)))
return f"CRKDH{max_seq + 1:07d}"
def _ensure_vehicle_exists(db: Session, tenant_no: str, vehicle_no: str) -> None:
vehicle_no = (vehicle_no or "").strip()
if not vehicle_no:
return
exists = (
db.query(DbVehicle.id)
.filter(
DbVehicle.tenant_no == tenant_no,
DbVehicle.del_flag == 0,
DbVehicle.vehicle_no == vehicle_no,
)
.first()
)
if exists:
return
db.add(
DbVehicle(
id=generate_uuid(),
tenant_no=tenant_no,
vehicle_no=vehicle_no,
remark="",
)
)
db.flush()
def find_monthly_db_plan(
db: Session,
tenant_no: str,
plan_date: date,
business_type: str,
customer_name: str,
product_id: str,
specification: Optional[str],
) -> Optional[DbPurchasePlan]:
month_start, month_end = _month_range(plan_date)
customer = (customer_name or "").strip()
spec = (specification or "").strip()
query = db.query(DbPurchasePlan).filter(
DbPurchasePlan.tenant_no == tenant_no,
DbPurchasePlan.del_flag == 0,
DbPurchasePlan.business_type == business_type,
DbPurchasePlan.product_id == product_id,
DbPurchasePlan.start_date <= month_end,
DbPurchasePlan.end_date >= month_start,
)
if customer:
query = query.filter(DbPurchasePlan.customer_name == customer)
if spec:
query = query.filter(DbPurchasePlan.specification == spec)
return query.order_by(DbPurchasePlan.create_time.desc()).first()
def _create_db_plan(
db: Session,
tenant_no: str,
plan: PlPlan,
product: PlPlanProduct,
business_type: str,
customer_name: str,
month_start: date,
month_end: date,
user_id: Optional[str],
dept_id: str,
) -> DbPurchasePlan:
snapshot = resolve_crm_product(db, tenant_no, product.product_id)
db_plan = DbPurchasePlan(
id=generate_uuid(),
tenant_no=tenant_no,
plan_no=generate_plan_no(),
plan_date=plan.plan_date,
start_date=month_start,
end_date=month_end,
business_type=business_type,
planned_quantity=Decimal(str(_product_quantity(product))),
vehicle_no=(plan.license_plate or "").strip(),
customer_name=customer_name or None,
remark=f"来源运输计划 {plan.plan_no}",
execution_status=default_execution_status(business_type),
executed_at=None,
last_weighing_slip_id=None,
executed_quantity=0,
auto_generate_enabled=0,
auto_generate_end_month=None,
auto_generate_last_month=None,
create_by=user_id,
create_dept_id=dept_id,
)
apply_product_snapshot_to_plan(db_plan, snapshot)
db.add(db_plan)
db.flush()
return db_plan
def _create_db_inventory(
db: Session,
tenant_no: str,
plan: PlPlan,
product: PlPlanProduct,
db_plan: DbPurchasePlan,
business_type: str,
customer_name: str,
license_plate: str,
user_id: Optional[str],
dept_id: str,
) -> DbInboundOutbound:
if license_plate:
_ensure_vehicle_exists(db, tenant_no, license_plate)
snapshot = resolve_crm_product(db, tenant_no, product.product_id)
status_value = "待入库" if business_type == "入库" else "待出库"
inventory = DbInboundOutbound(
id=next_inbound_outbound_id(db, tenant_no),
tenant_no=tenant_no,
date=plan.plan_date,
partner_company=customer_name,
business_type=business_type,
quantity=Decimal(str(_product_quantity(product))),
plan_no=(db_plan.plan_no or "").strip() or None,
batch_no=_generate_batch_no(db, tenant_no),
vehicle_no=(license_plate or "").strip(),
status=status_value,
remark=f"运输计划 {plan.plan_no}",
purchase_plan_id=db_plan.id,
create_by=user_id,
create_dept_id=dept_id,
)
apply_product_snapshot_to_inventory(inventory, snapshot)
db.add(inventory)
db.flush()
return inventory
# 仅这些状态的出入库单可在「再次安排+勾地磅」时软删后重建
_REVOKABLE_INVENTORY_STATUSES = frozenset({"待入库", "待出库", "待三方填写", "待处理"})
def _inventory_has_weighing_slip(db: Session, inventory_id: str) -> bool:
return (
db.query(DbWeighingSlip.id)
.filter(
DbWeighingSlip.inbound_outbound_id == inventory_id,
DbWeighingSlip.del_flag == 0,
DbWeighingSlip.is_voided == 0,
)
.first()
is not None
)
def revoke_regeneratable_dibang_for_transport(
db: Session,
*,
tenant_no: str,
transport_id: str,
user_id: Optional[str],
) -> None:
"""再次勾选地磅安排前:软删本运输单此前生成的、仍可作废的出入库单及关联。
- 不删除地磅月计划(可能被其他业务复用)
- 若出入库单已完成的/已有关联磅单 → 阻断并提示人工处理
"""
links = (
db.query(PlTransportDbLink)
.filter(
PlTransportDbLink.tenant_no == tenant_no,
PlTransportDbLink.transport_id == transport_id,
PlTransportDbLink.del_flag == 0,
)
.all()
)
if not links:
return
blocking: list[str] = []
for link in links:
inventory = (
db.query(DbInboundOutbound)
.filter(
DbInboundOutbound.id == link.db_inventory_id,
DbInboundOutbound.tenant_no == tenant_no,
DbInboundOutbound.del_flag == 0,
)
.first()
)
if not inventory:
link.del_flag = 1
link.update_by = user_id
continue
label = inventory.batch_no or inventory.id
status = (inventory.status or "").strip()
if status and status not in _REVOKABLE_INVENTORY_STATUSES:
blocking.append(f"{label}(状态:{status})")
continue
if _inventory_has_weighing_slip(db, inventory.id):
blocking.append(f"{label}(已关联地磅单)")
if blocking:
raise ValueError(
"以下出入库单已执行或已关联地磅,无法随运输安排自动重建:"
+ ";".join(blocking)
+ "。请在地磅管理中处理后再安排。"
)
for link in links:
inventory = (
db.query(DbInboundOutbound)
.filter(
DbInboundOutbound.id == link.db_inventory_id,
DbInboundOutbound.tenant_no == tenant_no,
DbInboundOutbound.del_flag == 0,
)
.first()
)
if inventory:
inventory.del_flag = 1
inventory.update_by = user_id
link.del_flag = 1
link.update_by = user_id
db.flush()
def sync_dibang_for_transport(
db: Session,
*,
tenant_no: str,
plan: PlPlan,
products: list[PlPlanProduct],
transport: PlTransport,
user_id: Optional[str],
dept_id: str,
) -> list[DibangInventoryLinkResult]:
business_type = _plan_type_to_business_type(plan.plan_type)
if not business_type:
return []
partner = resolve_partner_company(plan, plan.plan_type)
if not partner:
raise ValueError("无法解析往来单位,请检查合同供方/需方信息")
plan_date = plan.plan_date
if isinstance(plan_date, datetime):
plan_date = plan_date.date()
elif isinstance(plan_date, str):
parsed = parse_date_str(plan_date)
plan_date = parsed or date.today()
month_start, month_end = _month_range(plan_date)
license_plate = (transport.license_plate or plan.license_plate or "").strip()
# 计划/安排变更后再次勾地磅:先作废本运输单此前可重建的出入库单,再按当前计划重建
revoke_regeneratable_dibang_for_transport(
db,
tenant_no=tenant_no,
transport_id=transport.id,
user_id=user_id,
)
results: list[DibangInventoryLinkResult] = []
for product in products:
if not product.product_id:
raise ValueError(f"产品【{product.product_name}】未关联 CRM 产品,无法生成地磅计划")
db_plan = find_monthly_db_plan(
db,
tenant_no,
plan_date,
business_type,
partner,
product.product_id,
product.model,
)
if not db_plan:
db_plan = _create_db_plan(
db,
tenant_no,
plan,
product,
business_type,
partner,
month_start,
month_end,
user_id,
dept_id,
)
inventory = _create_db_inventory(
db,
tenant_no,
plan,
product,
db_plan,
business_type,
partner,
license_plate,
user_id,
dept_id,
)
link = PlTransportDbLink(
id=generate_uuid(),
tenant_no=tenant_no,
transport_id=transport.id,
plan_id=plan.id,
plan_product_id=product.id,
db_purchase_plan_id=db_plan.id,
db_inventory_id=inventory.id,
remark=f"运输计划 {plan.plan_no}",
create_by=user_id,
create_dept_id=dept_id,
)
db.add(link)
results.append(
DibangInventoryLinkResult(
plan_product_id=product.id,
product_name=product.product_name or "",
db_purchase_plan_id=db_plan.id,
db_inventory_id=inventory.id,
batch_no=inventory.batch_no or "",
plan_no=db_plan.plan_no or "",
)
)
return results
@@ -0,0 +1,208 @@
"""运输计划 - 人员 upsert 与车辆-人员关联保存"""
from __future__ import annotations
from typing import Optional
from fastapi import HTTPException
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.models.pl_models import PlPersonnel, PlVehiclePersonnel
from app.schemas.pl.base_data import VehiclePersonnelRow
def upsert_personnel(
db: Session,
tenant_no: str,
row: VehiclePersonnelRow,
*,
user_id: str,
dept_id: str,
) -> str:
"""按 personnelId → phone → name 弱匹配 upsert,返回 personnel_id。"""
personnel: Optional[PlPersonnel] = None
if row.personnel_id:
personnel = (
db.query(PlPersonnel)
.filter(
PlPersonnel.id == row.personnel_id,
PlPersonnel.tenant_no == tenant_no,
PlPersonnel.del_flag == 0,
)
.first()
)
phone = (row.phone_no or "").strip() or None
if personnel is None and phone:
personnel = (
db.query(PlPersonnel)
.filter(
PlPersonnel.tenant_no == tenant_no,
PlPersonnel.phone_no == phone,
PlPersonnel.del_flag == 0,
)
.first()
)
name = (row.personnel_name or "").strip()
if personnel is None and name:
personnel = (
db.query(PlPersonnel)
.filter(
PlPersonnel.tenant_no == tenant_no,
PlPersonnel.personnel_name == name,
PlPersonnel.del_flag == 0,
)
.first()
)
if personnel:
personnel.personnel_name = name or personnel.personnel_name
personnel.phone_no = phone
if row.age is not None:
personnel.age = row.age
personnel.update_by = user_id
return personnel.id
personnel = PlPersonnel(
id=generate_uuid(),
tenant_no=tenant_no,
personnel_name=name,
phone_no=phone,
age=row.age,
status="1",
create_by=user_id,
create_dept_id=dept_id,
)
db.add(personnel)
db.flush()
return personnel.id
def save_vehicle_personnel(
db: Session,
vehicle_id: str,
rows: list[VehiclePersonnelRow],
tenant_no: str,
*,
user_id: str,
dept_id: str,
) -> None:
"""软删旧关联后批量插入;校验默认司机唯一。"""
default_count = sum(
1 for r in rows if r.role == "driver" and r.is_default == 1
)
if default_count > 1:
raise HTTPException(status_code=400, detail="每辆车最多设置一名默认司机")
db.query(PlVehiclePersonnel).filter(
PlVehiclePersonnel.vehicle_id == vehicle_id,
PlVehiclePersonnel.tenant_no == tenant_no,
PlVehiclePersonnel.del_flag == 0,
).update({"del_flag": 1, "update_by": user_id}, synchronize_session=False)
for idx, row in enumerate(rows):
if row.role == "escort" and row.is_default == 1:
raise HTTPException(status_code=400, detail="仅司机角色可设为默认")
personnel_id = upsert_personnel(
db, tenant_no, row, user_id=user_id, dept_id=dept_id
)
link = PlVehiclePersonnel(
id=generate_uuid(),
tenant_no=tenant_no,
vehicle_id=vehicle_id,
personnel_id=personnel_id,
role=row.role,
is_default=row.is_default if row.role == "driver" else 0,
remark=row.remark,
order_num=idx,
create_by=user_id,
create_dept_id=dept_id,
)
db.add(link)
def build_personnel_summary(
links: list[tuple[str, str, int]],
) -> tuple[str, Optional[str]]:
"""links: [(personnel_name, role, is_default)] → (summary, default_driver_name)."""
role_labels = {"driver": "司机", "escort": "押运员"}
parts: list[str] = []
default_name: Optional[str] = None
for name, role, is_default in links:
label = role_labels.get(role, role)
parts.append(f"{name}({label})")
if role == "driver" and int(is_default) == 1:
default_name = name
return "、".join(parts), default_name
def load_vehicle_personnel_rows(
db: Session, tenant_no: str, vehicle_id: str
) -> list[VehiclePersonnelRow]:
"""查询车辆关联人员子表行。"""
rows = (
db.query(PlVehiclePersonnel, PlPersonnel)
.join(
PlPersonnel,
PlPersonnel.id == PlVehiclePersonnel.personnel_id,
)
.filter(
PlVehiclePersonnel.vehicle_id == vehicle_id,
PlVehiclePersonnel.tenant_no == tenant_no,
PlVehiclePersonnel.del_flag == 0,
PlPersonnel.del_flag == 0,
)
.order_by(PlVehiclePersonnel.order_num.asc(), PlVehiclePersonnel.create_time.asc())
.all()
)
return [
VehiclePersonnelRow(
personnel_id=p.personnel_id,
personnel_name=person.personnel_name,
phone_no=person.phone_no,
age=person.age,
role=p.role,
is_default=p.is_default,
remark=p.remark,
)
for p, person in rows
]
def load_vehicle_personnel_summaries(
db: Session, tenant_no: str, vehicle_ids: list[str]
) -> dict[str, tuple[str, Optional[str]]]:
"""批量加载 personnelSummary / defaultDriverName。"""
if not vehicle_ids:
return {}
rows = (
db.query(
PlVehiclePersonnel.vehicle_id,
PlPersonnel.personnel_name,
PlVehiclePersonnel.role,
PlVehiclePersonnel.is_default,
)
.join(PlPersonnel, PlPersonnel.id == PlVehiclePersonnel.personnel_id)
.filter(
PlVehiclePersonnel.vehicle_id.in_(vehicle_ids),
PlVehiclePersonnel.tenant_no == tenant_no,
PlVehiclePersonnel.del_flag == 0,
PlPersonnel.del_flag == 0,
)
.order_by(PlVehiclePersonnel.order_num.asc())
.all()
)
grouped: dict[str, list[tuple[str, str, str]]] = {}
for vehicle_id, name, role, is_default in rows:
grouped.setdefault(vehicle_id, []).append((name, role, is_default))
return {
vid: build_personnel_summary(items) for vid, items in grouped.items()
}
+697
View File
@@ -0,0 +1,697 @@
"""运输计划业务逻辑"""
from datetime import date
from decimal import Decimal
from typing import Optional
from fastapi import HTTPException
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.models.pl_models import (
PlCarrier,
PlPersonnel,
PlPlan,
PlPlanProduct,
PlPlanTransport,
PlTransport,
PlVehicle,
PlVehiclePersonnel,
)
from app.schemas.pl.plan import PlanCreateFull, PlanProductCreate, PlanTransportCreateBlock
def determine_plan_type(supplier_name: Optional[str], destination_name: Optional[str]) -> str:
if destination_name and ("安庆山峡" in destination_name or "安徽云栋" in destination_name):
return "inbound"
if supplier_name and ("安庆山峡" in supplier_name or "安徽云栋" in supplier_name):
return "outbound"
return "direct"
def _product_quantity(prod: PlanProductCreate) -> Decimal:
if prod.quantity is not None:
return Decimal(str(prod.quantity))
if prod.inbound_estimate_qty is not None:
return Decimal(str(prod.inbound_estimate_qty))
if prod.outbound_estimate_qty is not None:
return Decimal(str(prod.outbound_estimate_qty))
return Decimal("0")
def sum_product_quantities(products: list[PlanProductCreate]) -> Decimal:
return sum(_product_quantity(p) for p in products)
def _estimate_qty_fields(plan_type: str, qty: Optional[Decimal]) -> dict:
if qty is None:
return {}
q = float(qty)
if plan_type == "inbound":
return {"inbound_estimate_qty": q, "outbound_estimate_qty": q}
if plan_type == "outbound":
return {"outbound_estimate_qty": q, "inbound_estimate_qty": q}
return {"inbound_estimate_qty": q, "outbound_estimate_qty": q}
def build_plan_product(
*,
tenant_no: str,
plan_id: str,
plan_type: str,
prod: PlanProductCreate,
order_num: int,
user_id: str,
dept_id: str,
) -> PlPlanProduct:
qty = _product_quantity(prod)
estimates = _estimate_qty_fields(plan_type, qty if qty else None)
tax_price = prod.tax_price
return PlPlanProduct(
id=generate_uuid(),
tenant_no=tenant_no,
plan_id=plan_id,
product_id=prod.product_id,
product_no=prod.product_no,
product_name=prod.product_name,
model=prod.model,
unit=prod.unit or "吨",
category_name=prod.category_name,
package_spec=prod.package_spec,
delivery_method=prod.delivery_method,
quantity=qty if qty else None,
actual_qty=Decimal(str(prod.actual_qty)) if prod.actual_qty is not None else (qty if qty else None),
tax_price=tax_price,
tax_amount=prod.tax_amount,
tax_subtotal=prod.tax_subtotal,
is_explosive=prod.is_explosive,
is_toxic=prod.is_toxic,
purchase_cert_url=prod.purchase_cert_url,
transport_cert_url=prod.transport_cert_url,
inbound_price=tax_price,
outbound_price=tax_price,
inbound_amount=prod.tax_subtotal,
outbound_amount=prod.tax_subtotal,
remark=prod.remark,
order_num=order_num,
create_by=user_id,
create_dept_id=dept_id,
**estimates,
)
def _resolve_driver(
db: Session,
tenant_no: str,
vehicle_id: str,
driver_id: Optional[str],
) -> tuple[str, str, Optional[str]]:
if driver_id:
personnel = (
db.query(PlPersonnel)
.filter(
PlPersonnel.id == driver_id,
PlPersonnel.tenant_no == tenant_no,
PlPersonnel.del_flag == 0,
)
.first()
)
if personnel:
return personnel.id, personnel.personnel_name, personnel.phone_no
default_link = (
db.query(PlVehiclePersonnel)
.filter(
PlVehiclePersonnel.vehicle_id == vehicle_id,
PlVehiclePersonnel.tenant_no == tenant_no,
PlVehiclePersonnel.del_flag == 0,
PlVehiclePersonnel.role == "driver",
)
.order_by(PlVehiclePersonnel.is_default.desc(), PlVehiclePersonnel.order_num.asc())
.first()
)
if default_link:
personnel = (
db.query(PlPersonnel)
.filter(
PlPersonnel.id == default_link.personnel_id,
PlPersonnel.del_flag == 0,
)
.first()
)
if personnel:
return personnel.id, personnel.personnel_name, personnel.phone_no
raise HTTPException(status_code=400, detail="请选择司机或确保车辆已关联默认司机")
def _calc_freight_amount(
freight_type: str,
products: list[PlPlanProduct],
transport_qty: Optional[Decimal],
freight_price: Optional[Decimal],
freight_amount: Optional[Decimal],
) -> Decimal:
if freight_type == "by_trip":
return Decimal(str(freight_amount or 0))
qty = transport_qty
if qty is None:
qty = sum(
Decimal(str(p.quantity or p.inbound_estimate_qty or p.outbound_estimate_qty or 0))
for p in products
)
if freight_price is not None:
computed = qty * Decimal(str(freight_price))
if freight_amount is not None:
return Decimal(str(freight_amount))
return computed
return Decimal(str(freight_amount or 0))
def _validate_toxic_products(products: list[PlPlanProduct]) -> None:
for prod in products:
if prod.is_explosive or prod.is_toxic:
if not prod.purchase_cert_url or not prod.transport_cert_url:
label = "易制爆" if prod.is_explosive else "易制毒"
raise HTTPException(
status_code=400,
detail=f"产品【{prod.product_name}】为{label},必须上传购买证和运输证",
)
def resolve_hazard_flags_from_crm(
db: Session,
tenant_no: str,
product_id: Optional[str],
is_toxic: int = 0,
is_explosive: int = 0,
) -> tuple[int, int]:
if is_toxic or is_explosive:
return int(is_toxic or 0), int(is_explosive or 0)
if not product_id:
return 0, 0
from app.models.crm_models import CrmProduct
row = (
db.query(CrmProduct)
.filter(
CrmProduct.id == product_id,
CrmProduct.tenant_no == tenant_no,
CrmProduct.del_flag == 0,
)
.first()
)
if not row:
return 0, 0
return int(row.is_toxic or 0), int(row.is_explosive or 0)
def update_plan_product_certs(
db: Session,
*,
tenant_no: str,
plan_id: str,
items: list,
user_id: str,
) -> list[PlPlanProduct]:
plan = (
db.query(PlPlan)
.filter(
PlPlan.id == plan_id,
PlPlan.tenant_no == tenant_no,
PlPlan.del_flag == 0,
)
.first()
)
if not plan:
raise HTTPException(status_code=404, detail="计划不存在")
if plan.archive_status == "archived":
raise HTTPException(status_code=400, detail="已归档的计划不能修改")
updated: list[PlPlanProduct] = []
for item in items:
row = (
db.query(PlPlanProduct)
.filter(
PlPlanProduct.id == item.id,
PlPlanProduct.plan_id == plan_id,
PlPlanProduct.tenant_no == tenant_no,
PlPlanProduct.del_flag == 0,
)
.first()
)
if not row:
raise HTTPException(status_code=404, detail=f"计划产品不存在: {item.id}")
if not (row.is_toxic or row.is_explosive):
raise HTTPException(status_code=400, detail=f"产品【{row.product_name}】无需上传危化品证书")
row.purchase_cert_url = (item.purchase_cert_url or "").strip() or None
row.transport_cert_url = (item.transport_cert_url or "").strip() or None
row.update_by = user_id
updated.append(row)
plan.update_by = user_id
db.commit()
for row in updated:
db.refresh(row)
return updated
def _generate_transport_no(db: Session) -> str:
now = date.today()
prefix = f"SXYS{now.strftime('%Y%m')}"
last = (
db.query(PlTransport)
.filter(PlTransport.transport_no.like(f"{prefix}%"))
.order_by(PlTransport.transport_no.desc())
.first()
)
seq = 1
if last and last.transport_no:
try:
seq = int(last.transport_no[-6:]) + 1
except ValueError:
seq = 1
return f"{prefix}{seq:06d}"
def _resolve_transport_context(
db: Session,
*,
tenant_no: str,
plan: PlPlan,
transport_payload: PlanTransportCreateBlock,
products: list[PlPlanProduct],
) -> tuple[PlVehicle, str, str, Optional[str], Optional[str], Optional[str], Decimal, Optional[Decimal]]:
vehicle = (
db.query(PlVehicle)
.filter(
PlVehicle.id == transport_payload.vehicle_id,
PlVehicle.tenant_no == tenant_no,
PlVehicle.del_flag == 0,
)
.first()
)
if not vehicle:
raise HTTPException(status_code=400, detail="车辆不存在")
driver_id, driver_name, driver_phone = _resolve_driver(
db, tenant_no, transport_payload.vehicle_id, transport_payload.driver_id
)
carrier_id = transport_payload.carrier_id or vehicle.carrier_id
carrier_name = vehicle.carrier_name
if carrier_id:
carrier = (
db.query(PlCarrier)
.filter(PlCarrier.id == carrier_id, PlCarrier.del_flag == 0)
.first()
)
if carrier:
carrier_name = carrier.carrier_name
freight_amount = _calc_freight_amount(
transport_payload.freight_type,
products,
transport_payload.transport_qty,
transport_payload.freight_price,
transport_payload.freight_amount,
)
transport_qty = transport_payload.transport_qty
if transport_qty is None and transport_payload.freight_type == "by_weight":
transport_qty = sum(
Decimal(str(p.quantity or p.inbound_estimate_qty or p.outbound_estimate_qty or 0))
for p in products
)
return (
vehicle,
driver_id,
driver_name,
driver_phone,
carrier_id,
carrier_name,
freight_amount,
transport_qty,
)
def _apply_payload_to_transport_row(
transport: PlTransport,
*,
vehicle: PlVehicle,
driver_id: str,
driver_name: str,
driver_phone: Optional[str],
carrier_id: Optional[str],
carrier_name: Optional[str],
plan: PlPlan,
transport_payload: PlanTransportCreateBlock,
freight_amount: Decimal,
transport_qty: Optional[Decimal],
user_id: str,
) -> None:
transport.vehicle_id = vehicle.id
transport.license_plate = vehicle.license_plate
transport.driver_id = driver_id
transport.driver_name = driver_name
transport.driver_phone = driver_phone
transport.carrier_id = carrier_id
transport.carrier_name = carrier_name
transport.start_point = plan.pickup_address
transport.end_point = plan.destination_address or plan.destination_name
transport.distance_km = transport_payload.distance_km
transport.transport_qty = transport_qty
transport.freight_price = transport_payload.freight_price
transport.freight_amount = freight_amount or 0
transport.freight_type = transport_payload.freight_type
transport.has_invoice = transport_payload.has_invoice
transport.unit = "吨" if transport_payload.freight_type == "by_weight" else "趟"
if transport_payload.remark is not None:
transport.remark = transport_payload.remark
transport.update_by = user_id
def upsert_draft_transport_for_plan(
db: Session,
*,
tenant_no: str,
plan: PlPlan,
transport_payload: PlanTransportCreateBlock,
products: list[PlPlanProduct],
user_id: str,
dept_id: str,
) -> None:
"""写入/更新草稿运输单(pl_transport + pl_plan_transport),计划保持待安排。"""
(
vehicle,
driver_id,
driver_name,
driver_phone,
carrier_id,
carrier_name,
freight_amount,
transport_qty,
) = _resolve_transport_context(
db,
tenant_no=tenant_no,
plan=plan,
transport_payload=transport_payload,
products=products,
)
transport: Optional[PlTransport] = None
if plan.transport_id:
transport = (
db.query(PlTransport)
.filter(
PlTransport.id == plan.transport_id,
PlTransport.tenant_no == tenant_no,
PlTransport.del_flag == 0,
)
.first()
)
if transport:
_apply_payload_to_transport_row(
transport,
vehicle=vehicle,
driver_id=driver_id,
driver_name=driver_name,
driver_phone=driver_phone,
carrier_id=carrier_id,
carrier_name=carrier_name,
plan=plan,
transport_payload=transport_payload,
freight_amount=freight_amount,
transport_qty=transport_qty,
user_id=user_id,
)
if transport.transport_status == "draft":
pass
else:
transport_no = _generate_transport_no(db)
transport = PlTransport(
id=generate_uuid(),
tenant_no=tenant_no,
transport_no=transport_no,
transport_status="draft",
approval_status="none",
remark=transport_payload.remark,
create_by=user_id,
create_dept_id=dept_id,
)
db.add(transport)
db.flush()
db.add(
PlPlanTransport(
id=generate_uuid(),
tenant_no=tenant_no,
plan_id=plan.id,
transport_id=transport.id,
create_by=user_id,
create_dept_id=dept_id,
)
)
plan.transport_id = transport.id
plan.transport_no = transport_no
_apply_payload_to_transport_row(
transport,
vehicle=vehicle,
driver_id=driver_id,
driver_name=driver_name,
driver_phone=driver_phone,
carrier_id=carrier_id,
carrier_name=carrier_name,
plan=plan,
transport_payload=transport_payload,
freight_amount=freight_amount,
transport_qty=transport_qty,
user_id=user_id,
)
plan.vehicle_id = vehicle.id
plan.license_plate = vehicle.license_plate
plan.driver_id = driver_id
plan.driver_name = driver_name
plan.freight_amount = freight_amount or 0
if plan.transport_status != "arranged":
plan.transport_status = "pending"
def clear_draft_transport_for_plan(
db: Session,
*,
tenant_no: str,
plan: PlPlan,
user_id: str,
) -> None:
"""清除计划上的草稿运输单及车辆预选。"""
if plan.transport_id:
transport = (
db.query(PlTransport)
.filter(
PlTransport.id == plan.transport_id,
PlTransport.tenant_no == tenant_no,
PlTransport.del_flag == 0,
)
.first()
)
if transport and transport.transport_status == "draft":
transport.del_flag = 1
transport.update_by = user_id
db.query(PlPlanTransport).filter(
PlPlanTransport.plan_id == plan.id,
PlPlanTransport.transport_id == transport.id,
PlPlanTransport.tenant_no == tenant_no,
PlPlanTransport.del_flag == 0,
).update({"del_flag": 1, "update_by": user_id})
plan.transport_id = None
plan.transport_no = None
plan.vehicle_id = None
plan.license_plate = None
plan.driver_id = None
plan.driver_name = None
plan.freight_amount = 0
if plan.transport_status != "arranged":
plan.transport_status = "pending"
def sync_transport_prefill_for_plan(
db: Session,
*,
tenant_no: str,
plan: PlPlan,
transport_payload: PlanTransportCreateBlock,
products: list[PlPlanProduct],
user_id: str,
dept_id: str = "",
) -> None:
"""同步运输预选到草稿运输子表(pl_transport)。"""
upsert_draft_transport_for_plan(
db,
tenant_no=tenant_no,
plan=plan,
transport_payload=transport_payload,
products=products,
user_id=user_id,
dept_id=dept_id or user_id,
)
def apply_vehicle_prefill_to_plan(
db: Session,
*,
tenant_no: str,
plan: PlPlan,
transport_payload: PlanTransportCreateBlock,
products: list[PlPlanProduct],
user_id: str = "",
dept_id: str = "",
) -> None:
"""兼容旧调用:写入草稿运输子表。"""
upsert_draft_transport_for_plan(
db,
tenant_no=tenant_no,
plan=plan,
transport_payload=transport_payload,
products=products,
user_id=user_id,
dept_id=dept_id or user_id,
)
def create_transport_for_plan(
db: Session,
*,
tenant_no: str,
plan: PlPlan,
products: list[PlPlanProduct],
transport_payload: PlanTransportCreateBlock,
user_id: str,
dept_id: str,
generate_transport_no,
) -> PlTransport:
vehicle = (
db.query(PlVehicle)
.filter(
PlVehicle.id == transport_payload.vehicle_id,
PlVehicle.tenant_no == tenant_no,
PlVehicle.del_flag == 0,
)
.first()
)
if not vehicle:
raise HTTPException(status_code=400, detail="车辆不存在")
_validate_toxic_products(products)
driver_id, driver_name, driver_phone = _resolve_driver(
db, tenant_no, transport_payload.vehicle_id, transport_payload.driver_id
)
carrier_name = vehicle.carrier_name
carrier_id = transport_payload.carrier_id or vehicle.carrier_id
if carrier_id:
carrier = (
db.query(PlCarrier)
.filter(PlCarrier.id == carrier_id, PlCarrier.del_flag == 0)
.first()
)
if carrier:
carrier_name = carrier.carrier_name
freight_amount = _calc_freight_amount(
transport_payload.freight_type,
products,
transport_payload.transport_qty,
transport_payload.freight_price,
transport_payload.freight_amount,
)
transport_qty = transport_payload.transport_qty
if transport_qty is None and transport_payload.freight_type == "by_weight":
transport_qty = sum(
Decimal(str(p.quantity or p.inbound_estimate_qty or p.outbound_estimate_qty or 0))
for p in products
)
transport_no = generate_transport_no(db)
transport = PlTransport(
id=generate_uuid(),
tenant_no=tenant_no,
transport_no=transport_no,
vehicle_id=vehicle.id,
license_plate=vehicle.license_plate,
driver_id=driver_id,
driver_name=driver_name,
driver_phone=driver_phone,
carrier_id=carrier_id,
carrier_name=carrier_name,
start_point=plan.pickup_address,
end_point=plan.destination_address or plan.destination_name,
distance_km=transport_payload.distance_km,
unit="吨" if transport_payload.freight_type == "by_weight" else "趟",
transport_qty=transport_qty,
freight_price=transport_payload.freight_price,
freight_amount=freight_amount or 0,
freight_type=transport_payload.freight_type,
has_invoice=transport_payload.has_invoice,
transport_status="draft",
approval_status="none",
remark=transport_payload.remark,
create_by=user_id,
create_dept_id=dept_id,
)
db.add(transport)
db.add(
PlPlanTransport(
id=generate_uuid(),
tenant_no=tenant_no,
plan_id=plan.id,
transport_id=transport.id,
create_by=user_id,
create_dept_id=dept_id,
)
)
plan.transport_id = transport.id
plan.transport_no = transport_no
plan.vehicle_id = vehicle.id
plan.license_plate = vehicle.license_plate
plan.driver_id = driver_id
plan.driver_name = driver_name
plan.transport_status = "arranged"
plan.freight_amount = freight_amount or 0
return transport
def validate_create_full(payload: PlanCreateFull) -> None:
if not payload.contract_id:
raise HTTPException(status_code=422, detail="请选择合同")
if not payload.products:
raise HTTPException(status_code=422, detail="请至少保留一条产品明细")
transport = payload.transport
if not transport or not transport.vehicle_id:
return
if payload.has_freight:
if transport.freight_type == "by_weight":
if not transport.freight_price or Decimal(str(transport.freight_price)) <= 0:
raise HTTPException(status_code=422, detail="按重量计费时请填写运输单价")
qty = transport.transport_qty or sum_product_quantities(payload.products)
if qty <= 0:
raise HTTPException(status_code=422, detail="运输量必须大于0")
elif transport.freight_type == "by_trip":
if not transport.freight_amount or Decimal(str(transport.freight_amount)) <= 0:
raise HTTPException(status_code=422, detail="按趟计费时请填写运费金额")
def calc_plan_total_amount(products: list[PlanProductCreate]) -> Decimal:
total = Decimal("0")
for prod in products:
if prod.tax_subtotal is not None:
total += Decimal(str(prod.tax_subtotal))
return total
+104 -14
View File
@@ -1,9 +1,16 @@
"""报销单号/标题生成(从 bx-backend 迁移,增加 tenant_no 隔离)。"""
from datetime import datetime
from __future__ import annotations
from sqlalchemy import text
import re
from datetime import date, datetime
from sqlalchemy import func, text
from sqlalchemy.orm import Session
from app.models.bx_models import BxReimburseApply
_AUTO_TITLE_SUFFIX_RE = re.compile(r"报销单\d{11}$")
def generate_apply_code(db: Session, prefix: str, tenant_no: str) -> str:
"""
@@ -30,17 +37,100 @@ def generate_apply_code(db: Session, prefix: str, tenant_no: str) -> str:
return f"{prefix}{today}{seq:03d}"
def generate_title(db: Session, applicant_name: str, tenant_no: str) -> str:
today = datetime.now().strftime("%Y%m%d")
like_pattern = f"%报销单{today}%"
def parse_reimburse_date(value: str | date | datetime | None) -> date:
if value is None:
return datetime.now().date()
if isinstance(value, datetime):
return value.date()
if isinstance(value, date):
return value
text_value = str(value).strip()
if not text_value:
return datetime.now().date()
return datetime.strptime(text_value, "%Y-%m-%d").date()
result = db.execute(
text(
"SELECT COUNT(*) FROM bx_reimburse_apply "
"WHERE tenant_no = :tenant_no AND title LIKE :p AND del_flag = 0"
),
{"tenant_no": tenant_no, "p": like_pattern},
).scalar()
seq = (result or 0) + 1
return f"{applicant_name}报销单{today}{seq:03d}"
def format_reimburse_title(applicant_name: str, reimburse_date: date, seq: int) -> str:
return f"{applicant_name}报销单{reimburse_date.strftime('%Y%m%d')}{seq:03d}"
def is_auto_reimburse_title(title: str) -> bool:
return bool(_AUTO_TITLE_SUFFIX_RE.search(str(title or "").strip()))
def preview_reimburse_title_seq(
db: Session,
tenant_no: str,
reimburse_date: date,
exclude_apply_id: str | None = None,
) -> int:
"""预览序号(不加行锁,仅用于弹窗展示)。"""
query = db.query(func.max(BxReimburseApply.title_seq)).filter(
BxReimburseApply.tenant_no == tenant_no,
BxReimburseApply.reimburse_date == reimburse_date,
BxReimburseApply.del_flag == 0,
BxReimburseApply.title_seq.isnot(None),
)
if exclude_apply_id:
query = query.filter(BxReimburseApply.id != exclude_apply_id)
max_seq = query.scalar()
return int(max_seq or 0) + 1
def allocate_reimburse_title_seq(
db: Session,
tenant_no: str,
reimburse_date: date,
exclude_apply_id: str | None = None,
) -> int:
"""
分配同租户、同报销日期下的标题序号(MAX+1)。
配合 uk_tenant_reimburse_date_title_seq 唯一约束,并发冲突时由上层重试。
"""
query = db.query(func.max(BxReimburseApply.title_seq)).filter(
BxReimburseApply.tenant_no == tenant_no,
BxReimburseApply.reimburse_date == reimburse_date,
BxReimburseApply.del_flag == 0,
BxReimburseApply.title_seq.isnot(None),
)
if exclude_apply_id:
query = query.filter(BxReimburseApply.id != exclude_apply_id)
max_seq = query.with_for_update().scalar()
return int(max_seq or 0) + 1
def generate_title(
db: Session,
applicant_name: str,
tenant_no: str,
reimburse_date: str | date | datetime | None = None,
exclude_apply_id: str | None = None,
) -> str:
"""预览用标题生成(提交时仍会在服务端重新分配序号以保证并发安全)。"""
rd = parse_reimburse_date(reimburse_date)
seq = preview_reimburse_title_seq(db, tenant_no, rd, exclude_apply_id)
return format_reimburse_title(applicant_name, rd, seq)
def resolve_reimburse_title(
db: Session,
applicant_name: str,
tenant_no: str,
reimburse_date: date,
requested_title: str | None,
exclude_apply_id: str | None = None,
) -> tuple[str, int | None]:
"""
确定最终标题与 title_seq。
- 未填标题或仍为自动标题格式时:按报销日期重新分配序号并生成标题。
- 自定义标题:title_seq 为 None(不参与唯一序号约束)。
"""
custom_title = str(requested_title or "").strip()
if custom_title and not is_auto_reimburse_title(custom_title):
return custom_title, None
seq = allocate_reimburse_title_seq(
db, tenant_no, reimburse_date, exclude_apply_id=exclude_apply_id
)
title = format_reimburse_title(applicant_name, reimburse_date, seq)
return title, seq
+13 -8
View File
@@ -86,7 +86,6 @@
"84": "Community 84",
"85": "Community 85",
"86": "Community 86",
"87": "Community 87",
"88": "Community 88",
"89": "Community 89",
"90": "Community 90",
@@ -97,7 +96,6 @@
"95": "Community 95",
"96": "Community 96",
"97": "Community 97",
"98": "Community 98",
"99": "Community 99",
"100": "Community 100",
"101": "Community 101",
@@ -124,13 +122,20 @@
"122": "Community 122",
"123": "Community 123",
"124": "Community 124",
"125": "Community 125",
"126": "Community 126",
"127": "Community 127",
"128": "Community 128",
"129": "Community 129",
"130": "Community 130",
"131": "Community 131",
"132": "Community 132",
"133": "Community 133"
"133": "Community 133",
"134": "Community 134",
"135": "Community 135",
"136": "Community 136",
"137": "Community 137",
"138": "Community 138",
"139": "Community 139",
"140": "Community 140",
"141": "Community 141",
"143": "Community 143",
"144": "Community 144",
"146": "Community 146",
"147": "Community 147"
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "label": "freight.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L1"}, {"id": "pl_freight_freightsettlementbase", "label": "FreightSettlementBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_freight_freightsettlementcreate", "label": "FreightSettlementCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L23"}, {"id": "pl_freight_freightsettlementupdate", "label": "FreightSettlementUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L28"}, {"id": "pl_freight_freightsettlementread", "label": "FreightSettlementRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L37"}, {"id": "pl_freight_freightsettlementwithtransports", "label": "FreightSettlementWithTransports", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L51"}, {"id": "pl_freight_freightsettlementtransportread", "label": "FreightSettlementTransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L55"}, {"id": "pl_freight_remittancevouchercreate", "label": "RemittanceVoucherCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L70"}, {"id": "pl_freight_remittancevoucherread", "label": "RemittanceVoucherRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L79"}, {"id": "pl_freight_freightsettlementlistquery", "label": "FreightSettlementListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L96"}, {"id": "pl_freight_freightsettlementlistresponse", "label": "FreightSettlementListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L104"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "pl_freight_freightsettlementbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L14", "weight": 1.0}, {"source": "pl_freight_freightsettlementbase", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L14", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "pl_freight_freightsettlementcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L23", "weight": 1.0}, {"source": "pl_freight_freightsettlementcreate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L23", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L1"}, {"id": "pl_init_carrierbase", "label": "CarrierBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_init_carriercreate", "label": "CarrierCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L22"}, {"id": "pl_init_carrierupdate", "label": "CarrierUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L26"}, {"id": "pl_init_carrierread", "label": "CarrierRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L35"}, {"id": "pl_init_vehiclebase", "label": "VehicleBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L53"}, {"id": "pl_init_vehiclecreate", "label": "VehicleCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L65"}, {"id": "pl_init_vehicleupdate", "label": "VehicleUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L69"}, {"id": "pl_init_vehicleread", "label": "VehicleRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L82"}, {"id": "pl_init_driverbase", "label": "DriverBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L100"}, {"id": "pl_init_drivercreate", "label": "DriverCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L113"}, {"id": "pl_init_driverupdate", "label": "DriverUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L117"}, {"id": "pl_init_driverread", "label": "DriverRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L131"}, {"id": "pl_init_vehicledrivercreate", "label": "VehicleDriverCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L149"}, {"id": "pl_init_vehicledriverread", "label": "VehicleDriverRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L156"}, {"id": "pl_init_rationale_1", "label": "\u8fd0\u8f93\u8ba1\u5212\u7ba1\u7406 - Pydantic Schema", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "pl_init_carrierbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L14", "weight": 1.0}, {"source": "pl_init_carrierbase", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_personnel_service_py", "label": "pl_personnel_service.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L1"}, {"id": "services_pl_personnel_service_upsert_personnel", "label": "upsert_personnel()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L14"}, {"id": "services_pl_personnel_service_save_vehicle_personnel", "label": "save_vehicle_personnel()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L83"}, {"id": "services_pl_personnel_service_build_personnel_summary", "label": "build_personnel_summary()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L127"}, {"id": "services_pl_personnel_service_load_vehicle_personnel_rows", "label": "load_vehicle_personnel_rows()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L144"}, {"id": "services_pl_personnel_service_load_vehicle_personnel_summaries", "label": "load_vehicle_personnel_summaries()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L177"}, {"id": "services_pl_personnel_service_rationale_1", "label": "\u8fd0\u8f93\u8ba1\u5212 - \u4eba\u5458 upsert \u4e0e\u8f66\u8f86-\u4eba\u5458\u5173\u8054\u4fdd\u5b58", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L1"}, {"id": "services_pl_personnel_service_rationale_22", "label": "\u6309 personnelId \u2192 phone \u2192 name \u5f31\u5339\u914d upsert\uff0c\u8fd4\u56de personnel_id\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L22"}, {"id": "services_pl_personnel_service_rationale_130", "label": "links: [(personnel_name, role, is_default)] \u2192 (summary, default_driver_name).", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L130"}, {"id": "services_pl_personnel_service_rationale_180", "label": "\u6279\u91cf\u52a0\u8f7d personnelSummary / defaultDriverName\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L180"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_personnel_service_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_personnel_service_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_personnel_service_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_personnel_service_py", "target": "app_core_utils", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_personnel_service_py", "target": "app_models_pl_models", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L10", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_personnel_service_py", "target": "app_schemas_pl_base_data", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_personnel_service.py", "source_location": "L11", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_personnel_service_py", "target": "services_pl_personnel_service_upsert_personnel", "relation": "contains", "confidence": "EXTRACTED", "souLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_planproductbase", "label": "PlanProductBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_plan_planproductcreate", "label": "PlanProductCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L41"}, {"id": "pl_plan_planproductupdate", "label": "PlanProductUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L45"}, {"id": "pl_plan_planproductread", "label": "PlanProductRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L66"}, {"id": "pl_plan_planbase", "label": "PlanBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L80"}, {"id": "pl_plan_plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L116"}, {"id": "pl_plan_plantransportcreateblock", "label": "PlanTransportCreateBlock", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L122"}, {"id": "pl_plan_planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L136"}, {"id": "pl_plan_planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L172"}, {"id": "pl_plan_planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L195"}, {"id": "pl_plan_createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L204"}, {"id": "pl_plan_plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L212"}, {"id": "pl_plan_planlistquery", "label": "PlanListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L223"}, {"id": "pl_plan_planproductcertitem", "label": "PlanProductCertItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L238"}, {"id": "pl_plan_planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L245"}, {"id": "pl_plan_planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L250"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pl_plan_planproductbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13", "weight": 1.0}, {"source": "plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_crm_models_py", "label": "crm_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L1"}, {"id": "models_crm_models_crmproductcategory", "label": "CrmProductCategory", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L21"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_crm_models_crmproduct", "label": "CrmProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L43"}, {"id": "models_crm_models_sysoss", "label": "SysOss", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L78"}, {"id": "models_crm_models_crmcustomer", "label": "CrmCustomer", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L110"}, {"id": "models_crm_models_crmcontact", "label": "CrmContact", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L193"}, {"id": "models_crm_models_crminvoiceinfo", "label": "CrmInvoiceInfo", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L228"}, {"id": "models_crm_models_crmcustomerfollow", "label": "CrmCustomerFollow", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L256"}, {"id": "models_crm_models_crmcustomerpool", "label": "CrmCustomerPool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L287"}, {"id": "models_crm_models_crmcustomerpoolrule", "label": "CrmCustomerPoolRule", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L313"}, {"id": "models_crm_models_crmopportunity", "label": "CrmOpportunity", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L336"}, {"id": "models_crm_models_crmopportunityfollow", "label": "CrmOpportunityFollow", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L379"}, {"id": "models_crm_models_crmopportunityproduct", "label": "CrmOpportunityProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L410"}, {"id": "models_crm_models_crmopportunitystagelog", "label": "CrmOpportunityStageLog", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L440"}, {"id": "models_crm_models_crmcontract", "label": "CrmContract", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L471"}, {"id": "models_crm_models_crmcontractapproval", "label": "CrmContractApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L554"}, {"id": "models_crm_models_crmcontractchange", "label": "CrmContractChange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L585"}, {"id": "models_crm_models_crmcontracttemplate", "label": "CrmContractTemplate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L616"}, {"id": "models_crm_models_crmcontractproduct", "label": "CrmContractProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L650"}, {"id": "models_crm_models_crmcontractproductpricetier", "label": "CrmContractProductPriceTier", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L688"}, {"id": "models_crm_models_crmquote", "label": "CrmQuote", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L713"}, {"id": "models_crm_models_crmquoteproduct", "label": "CrmQuoteProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L771"}, {"id": "models_crm_models_crmquoteapproval", "label": "CrmQuoteApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py", "source_location": "L806"}, {"id": "models_crm_models_crmquotesharelog", "label": "CrmQuoteShareLogLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "label": "inventory.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L1"}, {"id": "pl_inventory_inventoryread", "label": "InventoryRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_inventory_inventorytransactionread", "label": "InventoryTransactionRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L36"}, {"id": "pl_inventory_inventorywarningread", "label": "InventoryWarningRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L57"}, {"id": "pl_inventory_inventorywarningupdate", "label": "InventoryWarningUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L72"}, {"id": "pl_inventory_inventorywarningthreshold", "label": "InventoryWarningThreshold", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L78"}, {"id": "pl_inventory_documentreminderread", "label": "DocumentReminderRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L90"}, {"id": "pl_inventory_documentreminderupdate", "label": "DocumentReminderUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L104"}, {"id": "pl_inventory_inventoryledgerquery", "label": "InventoryLedgerQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L115"}, {"id": "pl_inventory_inventoryledgerresponse", "label": "InventoryLedgerResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L122"}, {"id": "pl_inventory_inventorytransactionquery", "label": "InventoryTransactionQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L127"}, {"id": "pl_inventory_inventorytransactionresponse", "label": "InventoryTransactionResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L137"}, {"id": "pl_inventory_inventorysummaryquery", "label": "InventorySummaryQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L142"}, {"id": "pl_inventory_inventorysummaryitem", "label": "InventorySummaryItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L150"}, {"id": "pl_inventory_inventorysummaryresponse", "label": "InventorySummaryResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L159"}, {"id": "pl_inventory_transportstatsquery", "label": "TransportStatsQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L163"}, {"id": "pl_inventory_transportstatsitem", "label": "TransportStatsItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L170"}, {"id": "pl_inventory_transportstatsresponse", "label": "TransportStatsResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L177"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L4", "weight": 1.Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_base_data_py", "label": "base_data.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L1"}, {"id": "pl_base_data_list_carriers", "label": "list_carriers()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L35"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L35"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L35"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L35"}, {"id": "carrierread", "label": "CarrierRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L35"}, {"id": "pl_base_data_create_carrier", "label": "create_carrier()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L63"}, {"id": "carriercreate", "label": "CarrierCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L63"}, {"id": "pl_base_data_get_carrier", "label": "get_carrier()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L88"}, {"id": "pl_base_data_update_carrier", "label": "update_carrier()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L99"}, {"id": "carrierupdate", "label": "CarrierUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L99"}, {"id": "pl_base_data_delete_carrier", "label": "delete_carrier()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L118"}, {"id": "plcarrier", "label": "PlCarrier", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L130"}, {"id": "pl_base_data_list_vehicles", "label": "list_vehicles()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L151"}, {"id": "vehicleread", "label": "VehicleRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L151"}, {"id": "pl_base_data_create_vehicle", "label": "create_vehicle()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L182"}, {"id": "vehiclecreate", "label": "VehicleCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L182"}, {"id": "pl_base_data_get_vehicle", "label": "get_vehicle()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L223"}, {"id": "pl_base_data_update_vehicle", "label": "update_vehicle()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L234"}, {"id": "vehicleupdate", "label": "VehicleUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L234"}, {"id": "pl_base_data_delete_vehicle", "label": "delete_vehicle()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L253"}, {"id": "plvehicle", "label": "PlVehicle", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L265"}, {"id": "pl_base_data_list_drivers", "label": "list_drivers()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L286"}, {"id": "driverread", "label": "DriverRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L286"}, {"id": "pl_base_data_create_driver", "label": "create_driver()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L310"}, {"id": "drivercreate", "label": "DriverCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L310"}, {"id": "pl_base_data_get_driver", "label": "getLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_coerce_id", "label": "_coerce_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L9"}, {"id": "bx_reimburse_reimbursedetailcreate", "label": "ReimburseDetailCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L15"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_reimburse_reimbursedetailcreate_validate_expense_item_id", "label": ".validate_expense_item_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L24"}, {"id": "bx_reimburse_reimbursedetailout", "label": "ReimburseDetailOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L31"}, {"id": "bx_reimburse_reimburseapplycreate", "label": "ReimburseApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L41"}, {"id": "bx_reimburse_reimburseapplycreate_details_must_not_be_empty", "label": ".details_must_not_be_empty()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L51"}, {"id": "bx_reimburse_reimburseapplyupdate", "label": "ReimburseApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L57"}, {"id": "bx_reimburse_reimburseapplyout", "label": "ReimburseApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L65"}, {"id": "bx_reimburse_reimburseapprovalcreate", "label": "ReimburseApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L92"}, {"id": "bx_reimburse_reimburseapprovalout", "label": "ReimburseApprovalOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L99"}, {"id": "bx_reimburse_reimbursemystatsout", "label": "ReimburseMyStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L112"}, {"id": "bx_reimburse_reimburseapproverpendingstatsout", "label": "ReimburseApproverPendingStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L124"}, {"id": "bx_reimburse_payrequest", "label": "PayRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L131"}, {"id": "bx_reimburse_offsetrequest", "label": "OffsetRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L138"}, {"id": "bx_reimburse_offsetrequest_validate_advance_id", "label": ".validate_advance_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L147"}, {"id": "bx_reimburse_offsetitem", "label": "OffsetItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L154"}, {"id": "bx_reimburse_offsetitem_validate_advance_id", "label": ".validate_advance_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L162"}, {"id": "bx_reimburse_batchoffsetrequest", "label": "BatchOffsetRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L169"}, {"id": "bx_reimburse_reimburseoffsetrecordout", "label": "ReimburseOffsetRecordOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L177"}, {"id": "bx_reimburse_paymentfinancestatsout", "label": "PaymentFinanceStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L190"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L1"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_plan_service_py", "label": "pl_plan_service.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L1"}, {"id": "services_pl_plan_service_determine_plan_type", "label": "determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L23"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L23"}, {"id": "services_pl_plan_service_product_quantity", "label": "_product_quantity()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "planproductcreate", "label": "PlanProductCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "decimal", "label": "Decimal", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "services_pl_plan_service_sum_product_quantities", "label": "sum_product_quantities()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L41"}, {"id": "services_pl_plan_service_estimate_qty_fields", "label": "_estimate_qty_fields()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L45"}, {"id": "services_pl_plan_service_build_plan_product", "label": "build_plan_product()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "services_pl_plan_service_resolve_driver", "label": "_resolve_driver()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L101"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L101"}, {"id": "services_pl_plan_service_calc_freight_amount", "label": "_calc_freight_amount()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L146"}, {"id": "services_pl_plan_service_validate_toxic_products", "label": "_validate_toxic_products()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L170"}, {"id": "services_pl_plan_service_resolve_hazard_flags_from_crm", "label": "resolve_hazard_flags_from_crm()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L181"}, {"id": "services_pl_plan_service_update_plan_product_certs", "label": "update_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L208"}, {"id": "services_pl_plan_service_sync_transport_prefill_for_plan", "label": "sync_transport_prefill_for_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L258"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L258"}, {"id": "plantransportcreateblock", "label": "PlanTransportCreateBlock", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L258"}, {"id": "services_pl_plan_service_apply_vehicle_prefill_to_plan", "label": "apply_vehicle_prefill_to_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L350"}, {"id": "services_pl_plan_service_create_transport_for_plan", "label": "create_transport_for_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L403"}, {"id": "pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "soLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "label": "main.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L1"}, {"id": "app_main_lifespan", "label": "lifespan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L34"}, {"id": "fastapi", "label": "FastAPI", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L34"}, {"id": "app_main_error_json", "label": "_error_json()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L81"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L81"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L81"}, {"id": "jsonresponse", "label": "JSONResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L81"}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L94"}, {"id": "request", "label": "Request", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L94"}, {"id": "sqlalchemyerror", "label": "SQLAlchemyError", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L94"}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L105"}, {"id": "exception", "label": "Exception", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L105"}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L127"}, {"id": "app_main_root", "label": "root()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L149"}, {"id": "app_main_health_check", "label": "health_check()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L154"}, {"id": "app_main_rationale_95", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L95"}, {"id": "app_main_rationale_106", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L106"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "contextlib", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "logging", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "fastapi_middleware_cors", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "fastapi_responses", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L8", "weight": 1.0}, {"sLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_freight_py", "label": "freight.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L1"}, {"id": "pl_freight_generate_settlement_no", "label": "_generate_settlement_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L34"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L34"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L34"}, {"id": "pl_freight_list_settlements", "label": "list_settlements()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "freightsettlementlistresponse", "label": "FreightSettlementListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "pl_freight_create_settlement", "label": "create_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L97"}, {"id": "freightsettlementcreate", "label": "FreightSettlementCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L97"}, {"id": "freightsettlementread", "label": "FreightSettlementRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L97"}, {"id": "pl_freight_get_settlement", "label": "get_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L157"}, {"id": "freightsettlementwithtransports", "label": "FreightSettlementWithTransports", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L157"}, {"id": "pl_freight_update_settlement", "label": "update_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L194"}, {"id": "freightsettlementupdate", "label": "FreightSettlementUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L194"}, {"id": "pl_freight_submit_settlement", "label": "submit_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L219"}, {"id": "pl_freight_approve_settlement", "label": "approve_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L243"}, {"id": "pl_freight_create_voucher", "label": "create_voucher()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L267"}, {"id": "remittancevouchercreate", "label": "RemittanceVoucherCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L267"}, {"id": "remittancevoucherread", "label": "RemittanceVoucherRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L267"}, {"id": "pl_freight_list_vouchers", "label": "list_vouchers()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L296"}, {"id": "plfreightsettlement", "label": "PlFreightSettlement", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L321"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_freight_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_freight_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L49"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L49"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L49"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L71"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L76"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L85"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L85"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L106"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L106"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L106"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L106"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L106"}, {"id": "pl_plan_count_plans_by_contract", "label": "count_plans_by_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L205"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L234"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L234"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L234"}, {"id": "pl_plan_create_plan_full", "label": "create_plan_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L313"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L313"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L313"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L415"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L415"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L524"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L567"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L567"}, {"id": "pl_plan_patch_plan_product_certs", "label": "patch_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L685"}, {"id": "planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "label": "public_transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L1"}, {"id": "pl_public_transport_resolve_unit_label", "label": "_resolve_unit_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L27"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L27"}, {"id": "pl_public_transport_get_transport_by_token", "label": "_get_transport_by_token()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L34"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L34"}, {"id": "pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L34"}, {"id": "pl_public_transport_parse_feedback_images", "label": "_parse_feedback_images()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L48"}, {"id": "pl_public_transport_format_plan_date", "label": "_format_plan_date()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L60"}, {"id": "pl_public_transport_build_public_page", "label": "_build_public_page()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L70"}, {"id": "publictransportpageread", "label": "PublicTransportPageRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L70"}, {"id": "pl_public_transport_get_public_transport", "label": "get_public_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L134"}, {"id": "pl_public_transport_save_public_feedback", "label": "save_public_feedback()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L141"}, {"id": "publictransportfeedback", "label": "PublicTransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L141"}, {"id": "pl_public_transport_format_file_size", "label": "_format_file_size()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L162"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L162"}, {"id": "pl_public_transport_upload_public_attachment", "label": "upload_public_attachment()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L171"}, {"id": "uploadfile", "label": "UploadFile", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L171"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "json", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "os", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "fastapi", "relation": "imports_fLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_planproductbase", "label": "PlanProductBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_plan_planproductcreate", "label": "PlanProductCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L41"}, {"id": "pl_plan_planproductupdate", "label": "PlanProductUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L45"}, {"id": "pl_plan_planproductread", "label": "PlanProductRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L66"}, {"id": "pl_plan_planbase", "label": "PlanBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L80"}, {"id": "pl_plan_plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L116"}, {"id": "pl_plan_planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L122"}, {"id": "pl_plan_planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L151"}, {"id": "pl_plan_planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L174"}, {"id": "pl_plan_createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L183"}, {"id": "pl_plan_plantransportcreateblock", "label": "PlanTransportCreateBlock", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L191"}, {"id": "pl_plan_plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L205"}, {"id": "pl_plan_planlistquery", "label": "PlanListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L216"}, {"id": "pl_plan_planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L231"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pl_plan_planproductbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13", "weight": 1.0}, {"source": "pl_plan_planproductbase", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pl_plan_planproductcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/UsLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_crm_product_py", "label": "product.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L1"}, {"id": "crm_product_productcategorycreatebody", "label": "ProductCategoryCreateBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L12"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "crm_product_productcategoryupdatebody", "label": "ProductCategoryUpdateBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L26"}, {"id": "crm_product_categorydeletebody", "label": "CategoryDeleteBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L41"}, {"id": "crm_product_productupdatestatusbody", "label": "ProductUpdateStatusBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L47"}, {"id": "crm_product_productlistbody", "label": "ProductListBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L57"}, {"id": "crm_product_productcreatebody", "label": "ProductCreateBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L69"}, {"id": "crm_product_productupdatebody", "label": "ProductUpdateBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L101"}, {"id": "crm_product_productdetailbody", "label": "ProductDetailBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L134"}, {"id": "crm_product_productdeletebody", "label": "ProductDeleteBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L140"}, {"id": "crm_product_productoptionsbody", "label": "ProductOptionsBody", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L147"}, {"id": "crm_product_rationale_1", "label": "CRM \u4ea7\u54c1\u6a21\u5757 Pydantic Schemas", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_crm_product_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_crm_product_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_crm_product_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_crm_product_py", "target": "crm_product_productcategorycreatebody", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L12", "weight": 1.0}, {"source": "crm_product_productcategorycreatebody", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L12", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_crm_product_py", "target": "crm_product_productcategoryupdatebody", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L26", "weight": 1.0}, {"source": "crm_product_productcategoryupdatebody", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py", "source_location": "L26", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_crm_product_py", "target": "crm_product_categorydeletebody", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxiaLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L56"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L56"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L56"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L78"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L83"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L92"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L92"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L113"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L113"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L113"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L113"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L113"}, {"id": "pl_plan_count_plans_by_contract", "label": "count_plans_by_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L212"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L241"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L241"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L241"}, {"id": "pl_plan_create_plan_full", "label": "create_plan_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L320"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L320"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L320"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L424"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L424"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L533"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L576"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L576"}, {"id": "pl_plan_patch_plan_product_certs", "label": "patch_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L689"}, {"id": "planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "label": "bx_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L1"}, {"id": "models_bx_models_bxexpenseitem", "label": "BxExpenseItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L10"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_bx_models_bxworkflowdef", "label": "BxWorkflowDef", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L33"}, {"id": "models_bx_models_bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L62"}, {"id": "models_bx_models_bxadvanceapply", "label": "BxAdvanceApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L95"}, {"id": "models_bx_models_bxadvanceapproval", "label": "BxAdvanceApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L128"}, {"id": "models_bx_models_bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L151"}, {"id": "models_bx_models_bxreimbursedetail", "label": "BxReimburseDetail", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L189"}, {"id": "models_bx_models_bxreimburseapproval", "label": "BxReimburseApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L210"}, {"id": "models_bx_models_bxreimburseoffset", "label": "BxReimburseOffset", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L233"}, {"id": "models_bx_models_bxattachment", "label": "BxAttachment", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L251"}, {"id": "models_bx_models_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09\u6a21\u5757\u6570\u636e\u6a21\u578b \u2014 \u5bf9\u9f50 docs/sql/20260606_bx_tables.sql", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "sqlalchemy", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "app_core_database", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "models_bx_models_bxexpenseitem", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L10", "weight": 1.0}, {"source": "models_bx_models_bxexpenseitem", "target": "base", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L10", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "models_bx_models_bxworkflowdef", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L33", "weight": 1.0}, {"source": "models_bx_models_bxworkflowdef", "target": "base", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location":Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_planproductbase", "label": "PlanProductBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_plan_planproductcreate", "label": "PlanProductCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L41"}, {"id": "pl_plan_planproductupdate", "label": "PlanProductUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L45"}, {"id": "pl_plan_planproductread", "label": "PlanProductRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L66"}, {"id": "pl_plan_planbase", "label": "PlanBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L80"}, {"id": "pl_plan_plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L116"}, {"id": "pl_plan_planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L122"}, {"id": "pl_plan_planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L151"}, {"id": "pl_plan_planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L174"}, {"id": "pl_plan_createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L183"}, {"id": "pl_plan_plantransportcreateblock", "label": "PlanTransportCreateBlock", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L191"}, {"id": "pl_plan_plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L205"}, {"id": "pl_plan_planlistquery", "label": "PlanListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L216"}, {"id": "pl_plan_planproductcertitem", "label": "PlanProductCertItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L231"}, {"id": "pl_plan_planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L238"}, {"id": "pl_plan_planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L243"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pl_plan_planproductbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13", "weight": 1.0}, {"source": "plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_base_data_py", "label": "base_data.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L1"}, {"id": "pl_base_data_list_carriers", "label": "list_carriers()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L57"}, {"id": "pl_base_data_create_carrier", "label": "create_carrier()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L88"}, {"id": "pl_base_data_get_carrier", "label": "get_carrier()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L113"}, {"id": "pl_base_data_update_carrier", "label": "update_carrier()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L124"}, {"id": "pl_base_data_delete_carrier", "label": "delete_carrier()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L143"}, {"id": "pl_base_data_vehicle_to_read", "label": "_vehicle_to_read()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L175"}, {"id": "pl_base_data_vehicle_to_detail", "label": "_vehicle_to_detail()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L188"}, {"id": "pl_base_data_list_vehicles", "label": "list_vehicles()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L206"}, {"id": "pl_base_data_create_vehicle", "label": "create_vehicle()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L247"}, {"id": "pl_base_data_get_vehicle", "label": "get_vehicle()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L312"}, {"id": "pl_base_data_update_vehicle", "label": "update_vehicle()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L323"}, {"id": "pl_base_data_delete_vehicle", "label": "delete_vehicle()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L374"}, {"id": "pl_base_data_personnel_to_read", "label": "_personnel_to_read()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L406"}, {"id": "pl_base_data_personnel_to_detail", "label": "_personnel_to_detail()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L415"}, {"id": "pl_base_data_list_personnel", "label": "list_personnel()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L429"}, {"id": "pl_base_data_create_personnel", "label": "create_personnel()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L461"}, {"id": "pl_base_data_get_personnel", "label": "get_personnel()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L503"}, {"id": "pl_base_data_update_personnel", "label": "update_personnel()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L514"}, {"id": "pl_base_data_delete_personnel", "label": "delete_personnel()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L552"}, {"id": "pl_base_data_personnel_to_driver_read", "label": "_personnel_to_driver_read()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L584"}, {"id": "pl_base_data_list_drivers", "label": "list_drivers()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L603"}, {"id": "pl_base_data_create_driver", "label": "create_driver()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L630"}, {"id": "pl_base_data_get_driver", "label": "get_driver()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/base_data.py", "source_location": "L655"}, {"id": "pl_base_data_update_driver", "label": "update_driver()", "file_type": "code", "source_file": "/UsLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_plan_service_py", "label": "pl_plan_service.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L1"}, {"id": "services_pl_plan_service_determine_plan_type", "label": "determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L23"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L23"}, {"id": "services_pl_plan_service_product_quantity", "label": "_product_quantity()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "planproductcreate", "label": "PlanProductCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "decimal", "label": "Decimal", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "services_pl_plan_service_sum_product_quantities", "label": "sum_product_quantities()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L41"}, {"id": "services_pl_plan_service_estimate_qty_fields", "label": "_estimate_qty_fields()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L45"}, {"id": "services_pl_plan_service_build_plan_product", "label": "build_plan_product()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "services_pl_plan_service_resolve_driver", "label": "_resolve_driver()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L101"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L101"}, {"id": "services_pl_plan_service_calc_freight_amount", "label": "_calc_freight_amount()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L146"}, {"id": "services_pl_plan_service_validate_toxic_products", "label": "_validate_toxic_products()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L170"}, {"id": "services_pl_plan_service_resolve_hazard_flags_from_crm", "label": "resolve_hazard_flags_from_crm()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L181"}, {"id": "services_pl_plan_service_update_plan_product_certs", "label": "update_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L208"}, {"id": "services_pl_plan_service_generate_transport_no", "label": "_generate_transport_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L258"}, {"id": "services_pl_plan_service_resolve_transport_context", "label": "_resolve_transport_context()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L276"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L276"}, {"id": "plantransportcreateblock", "label": "PlanTransportCreateBlock", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L276"}, {"id": "plvehicle", "label": "PlVehicle", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L276"}, {"id": "services_pl_plan_service_apply_payload_to_transport_row", "label": "_apply_payload_to_transport_row()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L3Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L50"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L50"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L50"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L72"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L77"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L86"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L86"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "pl_plan_count_plans_by_contract", "label": "count_plans_by_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L206"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L235"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L235"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L235"}, {"id": "pl_plan_create_plan_full", "label": "create_plan_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L314"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L314"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L314"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L418"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L418"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L527"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L570"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L570"}, {"id": "pl_plan_patch_plan_product_certs", "label": "patch_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L683"}, {"id": "planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_cert_service_py", "label": "pl_cert_service.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L1"}, {"id": "services_pl_cert_service_list_owner_certs", "label": "list_owner_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L14"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L14"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L14"}, {"id": "plcert", "label": "PlCert", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L14"}, {"id": "services_pl_cert_service_certs_to_read", "label": "certs_to_read()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L30"}, {"id": "certread", "label": "CertRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L30"}, {"id": "services_pl_cert_service_normalize_cert_row", "label": "_normalize_cert_row()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L51"}, {"id": "certrow", "label": "CertRow", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L51"}, {"id": "services_pl_cert_service_save_owner_certs", "label": "save_owner_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L57"}, {"id": "services_pl_cert_service_nearest_expire_date", "label": "nearest_expire_date()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L111"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L111"}, {"id": "services_pl_cert_service_resolve_owner_label", "label": "_resolve_owner_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L129"}, {"id": "services_pl_cert_service_scan_cert_expiry", "label": "scan_cert_expiry()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L156"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L156"}, {"id": "services_pl_cert_service_rationale_67", "label": "\u6309 cert_id upsert\uff1b\u672a\u51fa\u73b0\u5728\u5217\u8868\u4e2d\u7684\u65e7\u8bc1\u8f6f\u5220\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L67"}, {"id": "services_pl_cert_service_rationale_157", "label": "\u626b\u63cf pl_cert \u751f\u6210\u5230\u671f\u63d0\u9192\uff0c\u8fd4\u56de\u65b0\u5efa\u6761\u6570\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L157"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_cert_service_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_cert_service_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_cert_service_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_cert_service_py", "target": "app_core_utils", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_cert_service.py", "source_location": "L9", "weighLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_pl_models_py", "label": "pl_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L1"}, {"id": "models_pl_models_plcarrier", "label": "PlCarrier", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L28"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_pl_models_plvehicle", "label": "PlVehicle", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L49"}, {"id": "models_pl_models_plpersonnel", "label": "PlPersonnel", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L74"}, {"id": "models_pl_models_plcert", "label": "PlCert", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L96"}, {"id": "models_pl_models_pldriver", "label": "PlDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L121"}, {"id": "models_pl_models_plvehiclepersonnel", "label": "PlVehiclePersonnel", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L147"}, {"id": "models_pl_models_plvehicledriver", "label": "PlVehicleDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L168"}, {"id": "models_pl_models_plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L193"}, {"id": "models_pl_models_plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L276"}, {"id": "models_pl_models_plplanchange", "label": "PlPlanChange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L330"}, {"id": "models_pl_models_pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L357"}, {"id": "models_pl_models_plplantransport", "label": "PlPlanTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L416"}, {"id": "models_pl_models_pltransportapproval", "label": "PlTransportApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L435"}, {"id": "models_pl_models_plfreightsettlement", "label": "PlFreightSettlement", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L464"}, {"id": "models_pl_models_plfreightsettlementtransport", "label": "PlFreightSettlementTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L495"}, {"id": "models_pl_models_plremittancevoucher", "label": "PlRemittanceVoucher", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L515"}, {"id": "models_pl_models_plinventory", "label": "PlInventory", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L542"}, {"id": "models_pl_models_plinventorytransaction", "label": "PlInventoryTransaction", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L574"}, {"id": "models_pl_models_plinventorywarning", "label": "PlInventoryWarning", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L603"}, {"id": "models_pl_models_pldocumentreminder", "label": "PlDocumentReminder", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L628"}, {"id": "models_pl_models_rationale_122", "label": "\u53f8\u673a\u8868 pl_driver\uff08\u517c\u5bb9\u65e7\u8868\uff0c\u8fc1\u79fb\u540e\u9010\u6b65\u5e9f\u5f03\uff09", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L122"}, {"id": "models_pl_models_rationale_148", "label": "\u8f66\u8f86-\u4eba\u5458\u5173\u8054\u8868 pl_vehicle_personnel", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L148"}, {"id": "models_pl_models_raLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_inventory_py", "label": "inventory.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L1"}, {"id": "pl_inventory_get_inventory_ledger", "label": "get_inventory_ledger()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "inventoryledgerresponse", "label": "InventoryLedgerResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "pl_inventory_set_warning_threshold", "label": "set_warning_threshold()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L76"}, {"id": "inventorywarningthreshold", "label": "InventoryWarningThreshold", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L76"}, {"id": "pl_inventory_list_warnings", "label": "list_warnings()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L124"}, {"id": "inventorywarningread", "label": "InventoryWarningRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L124"}, {"id": "pl_inventory_update_warning", "label": "update_warning()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L142"}, {"id": "inventorywarningupdate", "label": "InventoryWarningUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L142"}, {"id": "pl_inventory_list_transactions", "label": "list_transactions()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L181"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L181"}, {"id": "inventorytransactionresponse", "label": "InventoryTransactionResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L181"}, {"id": "pl_inventory_get_summary", "label": "get_summary()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L222"}, {"id": "inventorysummaryresponse", "label": "InventorySummaryResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L222"}, {"id": "pl_inventory_list_document_reminders", "label": "list_document_reminders()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L283"}, {"id": "documentreminderread", "label": "DocumentReminderRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L283"}, {"id": "pl_inventory_update_document_reminder", "label": "update_document_reminder()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L301"}, {"id": "documentreminderupdate", "label": "DocumentReminderUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L301"}, {"id": "pl_inventory_check_document_expiry", "label": "check_document_expiry()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L337"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_inventory_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_inventory_py", "Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "label": "freight.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L1"}, {"id": "pl_freight_freightsettlementbase", "label": "FreightSettlementBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_freight_freightsettlementcreate", "label": "FreightSettlementCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L23"}, {"id": "pl_freight_freightsettlementupdate", "label": "FreightSettlementUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L28"}, {"id": "pl_freight_freightsettlementread", "label": "FreightSettlementRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L37"}, {"id": "pl_freight_freightsettlementwithtransports", "label": "FreightSettlementWithTransports", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L51"}, {"id": "pl_freight_freightsettlementtransportread", "label": "FreightSettlementTransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L55"}, {"id": "pl_freight_remittancevouchercreate", "label": "RemittanceVoucherCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L70"}, {"id": "pl_freight_remittancevoucherread", "label": "RemittanceVoucherRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L79"}, {"id": "pl_freight_freightsettlementlistquery", "label": "FreightSettlementListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L96"}, {"id": "pl_freight_freightsettlementlistresponse", "label": "FreightSettlementListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L104"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "pl_freight_freightsettlementbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L14", "weight": 1.0}, {"source": "pl_freight_freightsettlementbase", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L14", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target": "pl_freight_freightsettlementcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L23", "weight": 1.0}, {"source": "pl_freight_freightsettlementcreate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/freight.py", "source_location": "L23", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_freight_py", "target"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_planproductbase", "label": "PlanProductBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_plan_planproductcreate", "label": "PlanProductCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L41"}, {"id": "pl_plan_planproductupdate", "label": "PlanProductUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L45"}, {"id": "pl_plan_planproductread", "label": "PlanProductRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L66"}, {"id": "pl_plan_planbase", "label": "PlanBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L80"}, {"id": "pl_plan_plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L116"}, {"id": "pl_plan_plantransportcreateblock", "label": "PlanTransportCreateBlock", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L122"}, {"id": "pl_plan_planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L136"}, {"id": "pl_plan_planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L172"}, {"id": "pl_plan_planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L201"}, {"id": "pl_plan_createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L210"}, {"id": "pl_plan_plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L218"}, {"id": "pl_plan_planlistquery", "label": "PlanListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L229"}, {"id": "pl_plan_planproductcertitem", "label": "PlanProductCertItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L244"}, {"id": "pl_plan_planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L251"}, {"id": "pl_plan_planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L256"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pl_plan_planproductbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13", "weight": 1.0}, {"source": "plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "label": "transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L1"}, {"id": "pl_transport_transportbase", "label": "TransportBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_transport_transportcreate", "label": "TransportCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L38"}, {"id": "pl_transport_transportarrange", "label": "TransportArrange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L43"}, {"id": "pl_transport_transportupdate", "label": "TransportUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L60"}, {"id": "pl_transport_transportread", "label": "TransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L84"}, {"id": "pl_transport_transportwithplans", "label": "TransportWithPlans", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L103"}, {"id": "pl_transport_transportfeedback", "label": "TransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L112"}, {"id": "pl_transport_approvalsubmit", "label": "ApprovalSubmit", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L126"}, {"id": "pl_transport_approvalrequest", "label": "ApprovalRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L131"}, {"id": "pl_transport_approvalrecordread", "label": "ApprovalRecordRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L137"}, {"id": "pl_transport_transportlistquery", "label": "TransportListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L156"}, {"id": "pl_transport_transportlistresponse", "label": "TransportListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L168"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "pl_transport_transportbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L14", "weight": 1.0}, {"source": "pl_transport_transportbase", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L14", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "pl_transport_transportcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L38", "weight": 1.0}, {"source": "pl_transport_transportcreate", "Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_transport_py", "label": "transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L1"}, {"id": "pl_transport_generate_transport_no", "label": "_generate_transport_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L40"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L40"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L40"}, {"id": "pl_transport_get_vehicle_info", "label": "_get_vehicle_info()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L64"}, {"id": "pl_transport_list_transports", "label": "list_transports()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L91"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L91"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L91"}, {"id": "transportlistresponse", "label": "TransportListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L91"}, {"id": "pl_transport_create_transport", "label": "create_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L146"}, {"id": "transportcreate", "label": "TransportCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L146"}, {"id": "transportread", "label": "TransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L146"}, {"id": "pl_transport_arrange_transport", "label": "arrange_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L218"}, {"id": "transportarrange", "label": "TransportArrange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L218"}, {"id": "pl_transport_get_transport", "label": "get_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L364"}, {"id": "pl_transport_qrcoderesponse", "label": "QrCodeResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L379"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_transport_generate_qrcode", "label": "generate_qrcode()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L389"}, {"id": "pl_transport_transport_scan_feedback", "label": "transport_scan_feedback()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L422"}, {"id": "transportfeedback", "label": "TransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L422"}, {"id": "pl_transport_submit_approval", "label": "submit_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L463"}, {"id": "approvalsubmit", "label": "ApprovalSubmit", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L463"}, {"id": "pl_transport_process_approval", "label": "process_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L508"}, {"id": "approvalrequest", "label": "ApprovalRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L508"}, {"id": "approvalrecordread", "label": "ApprovalRecordRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L508"}, {"id": "pl_transport_get_transport_approvals", "label": "get_transport_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "label": "transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L1"}, {"id": "pl_transport_transportbase", "label": "TransportBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_transport_transportcreate", "label": "TransportCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L37"}, {"id": "pl_transport_transportarrange", "label": "TransportArrange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L42"}, {"id": "pl_transport_transportupdate", "label": "TransportUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L59"}, {"id": "pl_transport_transportread", "label": "TransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L83"}, {"id": "pl_transport_transportwithplans", "label": "TransportWithPlans", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L102"}, {"id": "pl_transport_transportfeedback", "label": "TransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L111"}, {"id": "pl_transport_approvalsubmit", "label": "ApprovalSubmit", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L125"}, {"id": "pl_transport_approvalrequest", "label": "ApprovalRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L130"}, {"id": "pl_transport_approvalrecordread", "label": "ApprovalRecordRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L136"}, {"id": "pl_transport_transportlistquery", "label": "TransportListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L155"}, {"id": "pl_transport_transportlistresponse", "label": "TransportListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L167"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "pl_transport_transportbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L14", "weight": 1.0}, {"source": "pl_transport_transportbase", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L14", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "pl_transport_transportcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L37", "weight": 1.0}, {"source": "pl_transport_transportcreate", "Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "label": "main.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L1"}, {"id": "app_main_lifespan", "label": "lifespan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L35"}, {"id": "fastapi", "label": "FastAPI", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L35"}, {"id": "app_main_error_json", "label": "_error_json()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L82"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L82"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L82"}, {"id": "jsonresponse", "label": "JSONResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L82"}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L95"}, {"id": "request", "label": "Request", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L95"}, {"id": "sqlalchemyerror", "label": "SQLAlchemyError", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L95"}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L106"}, {"id": "exception", "label": "Exception", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L106"}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L129"}, {"id": "app_main_root", "label": "root()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L151"}, {"id": "app_main_health_check", "label": "health_check()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L156"}, {"id": "app_main_rationale_96", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L96"}, {"id": "app_main_rationale_107", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L107"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "contextlib", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "logging", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "fastapi_middleware_cors", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "fastapi_responses", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L8", "weight": 1.0}, {"sLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_pl_models_py", "label": "pl_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L1"}, {"id": "models_pl_models_plcarrier", "label": "PlCarrier", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L28"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_pl_models_plvehicle", "label": "PlVehicle", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L49"}, {"id": "models_pl_models_pldriver", "label": "PlDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L74"}, {"id": "models_pl_models_plvehicledriver", "label": "PlVehicleDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L100"}, {"id": "models_pl_models_plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L125"}, {"id": "models_pl_models_plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L202"}, {"id": "models_pl_models_plplanchange", "label": "PlPlanChange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L249"}, {"id": "models_pl_models_pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L276"}, {"id": "models_pl_models_plplantransport", "label": "PlPlanTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L334"}, {"id": "models_pl_models_pltransportapproval", "label": "PlTransportApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L353"}, {"id": "models_pl_models_plfreightsettlement", "label": "PlFreightSettlement", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L382"}, {"id": "models_pl_models_plfreightsettlementtransport", "label": "PlFreightSettlementTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L413"}, {"id": "models_pl_models_plremittancevoucher", "label": "PlRemittanceVoucher", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L433"}, {"id": "models_pl_models_plinventory", "label": "PlInventory", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L460"}, {"id": "models_pl_models_plinventorytransaction", "label": "PlInventoryTransaction", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L492"}, {"id": "models_pl_models_plinventorywarning", "label": "PlInventoryWarning", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L521"}, {"id": "models_pl_models_pldocumentreminder", "label": "PlDocumentReminder", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L546"}, {"id": "models_pl_models_rationale_101", "label": "\u8f66\u8f86-\u53f8\u673a\u5173\u8054\u8868 pl_vehicle_driver", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L101"}, {"id": "models_pl_models_rationale_203", "label": "\u8ba1\u5212\u4ea7\u54c1\u660e\u7ec6\u8868 pl_plan_product", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L203"}, {"id": "models_pl_models_rationale_250", "label": "\u8ba1\u5212\u53d8\u66f4\u8bb0\u5f55\u8868 pl_plan_change", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L250"}, {"id": "models_pl_models_rationale_335", "label": "\u8ba1\u5212-\u8fd0\u8f93\u5173\u8054\u8868 pl_plan_transport", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L335"}, {"id": "models_pl_models_rationale_354", "label": "\u8fd0\u8f93\u5ba1\u6279\u8bb0\u5f55\u8868 pl_transport_approval", "file_type": "rationale", "source_file": "/Users/zlwu/woLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "label": "inventory.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L1"}, {"id": "pl_inventory_inventoryread", "label": "InventoryRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_inventory_inventorytransactionread", "label": "InventoryTransactionRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L36"}, {"id": "pl_inventory_inventorywarningread", "label": "InventoryWarningRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L57"}, {"id": "pl_inventory_inventorywarningupdate", "label": "InventoryWarningUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L72"}, {"id": "pl_inventory_inventorywarningthreshold", "label": "InventoryWarningThreshold", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L78"}, {"id": "pl_inventory_documentreminderread", "label": "DocumentReminderRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L90"}, {"id": "pl_inventory_documentreminderupdate", "label": "DocumentReminderUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L104"}, {"id": "pl_inventory_inventoryledgerquery", "label": "InventoryLedgerQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L115"}, {"id": "pl_inventory_inventoryledgerresponse", "label": "InventoryLedgerResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L122"}, {"id": "pl_inventory_inventorytransactionquery", "label": "InventoryTransactionQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L127"}, {"id": "pl_inventory_inventorytransactionresponse", "label": "InventoryTransactionResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L137"}, {"id": "pl_inventory_inventorysummaryquery", "label": "InventorySummaryQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L142"}, {"id": "pl_inventory_inventorysummaryitem", "label": "InventorySummaryItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L150"}, {"id": "pl_inventory_inventorysummaryresponse", "label": "InventorySummaryResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L159"}, {"id": "pl_inventory_transportstatsquery", "label": "TransportStatsQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L163"}, {"id": "pl_inventory_transportstatsitem", "label": "TransportStatsItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L170"}, {"id": "pl_inventory_transportstatsresponse", "label": "TransportStatsResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L177"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L4", "weight": 1.Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L1"}, {"id": "pl_init_carrierbase", "label": "CarrierBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L150"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_init_carriercreate", "label": "CarrierCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L158"}, {"id": "pl_init_carrierupdate", "label": "CarrierUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L162"}, {"id": "pl_init_carrierread", "label": "CarrierRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L171"}, {"id": "pl_init_vehiclebase", "label": "VehicleBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L189"}, {"id": "pl_init_vehiclecreate", "label": "VehicleCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L201"}, {"id": "pl_init_vehicleupdate", "label": "VehicleUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L205"}, {"id": "pl_init_vehicleread", "label": "VehicleRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L218"}, {"id": "pl_init_driverbase", "label": "DriverBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L236"}, {"id": "pl_init_drivercreate", "label": "DriverCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L249"}, {"id": "pl_init_driverupdate", "label": "DriverUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L253"}, {"id": "pl_init_driverread", "label": "DriverRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L267"}, {"id": "pl_init_vehicledrivercreate", "label": "VehicleDriverCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L285"}, {"id": "pl_init_vehicledriverread", "label": "VehicleDriverRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L292"}, {"id": "pl_init_rationale_1", "label": "\u8fd0\u8f93\u8ba1\u5212\u7ba1\u7406 - Pydantic Schema", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "app_schemas_pl_plan", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "app_schemas_pl_transport", "relation": "imports_from",Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "label": "public_transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L1"}, {"id": "pl_public_transport_get_transport_by_token", "label": "_get_transport_by_token()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L24"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L24"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L24"}, {"id": "pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L24"}, {"id": "pl_public_transport_parse_feedback_images", "label": "_parse_feedback_images()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L38"}, {"id": "pl_public_transport_format_plan_date", "label": "_format_plan_date()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L50"}, {"id": "pl_public_transport_build_public_page", "label": "_build_public_page()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L60"}, {"id": "publictransportpageread", "label": "PublicTransportPageRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L60"}, {"id": "pl_public_transport_get_public_transport", "label": "get_public_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L119"}, {"id": "pl_public_transport_save_public_feedback", "label": "save_public_feedback()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L126"}, {"id": "publictransportfeedback", "label": "PublicTransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L126"}, {"id": "pl_public_transport_format_file_size", "label": "_format_file_size()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L147"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L147"}, {"id": "pl_public_transport_upload_public_attachment", "label": "upload_public_attachment()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L156"}, {"id": "uploadfile", "label": "UploadFile", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L156"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "json", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "os", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_sLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L1"}, {"id": "pl_init_rationale_1", "label": "\u8fd0\u8f93\u8ba1\u5212\u7ba1\u7406 - Pydantic Schema", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "app_schemas_pl_base_data", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "app_schemas_pl_plan", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L27", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "app_schemas_pl_transport", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L41", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "app_schemas_pl_freight", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L54", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "target": "app_schemas_pl_inventory", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L66", "weight": 1.0}, {"source": "pl_init_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_init_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_dibang_bridge_service_py", "label": "pl_dibang_bridge_service.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L1"}, {"id": "services_pl_dibang_bridge_service_dibanginventorylinkresult", "label": "DibangInventoryLinkResult", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L27"}, {"id": "services_pl_dibang_bridge_service_resolve_partner_company", "label": "resolve_partner_company()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L36"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L36"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L36"}, {"id": "services_pl_dibang_bridge_service_month_range", "label": "_month_range()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L44"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L44"}, {"id": "services_pl_dibang_bridge_service_plan_type_to_business_type", "label": "_plan_type_to_business_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L51"}, {"id": "services_pl_dibang_bridge_service_product_quantity", "label": "_product_quantity()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L59"}, {"id": "plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L59"}, {"id": "float", "label": "float", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L59"}, {"id": "services_pl_dibang_bridge_service_generate_batch_no", "label": "_generate_batch_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L66"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L66"}, {"id": "services_pl_dibang_bridge_service_ensure_vehicle_exists", "label": "_ensure_vehicle_exists()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L86"}, {"id": "services_pl_dibang_bridge_service_find_monthly_db_plan", "label": "find_monthly_db_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L112"}, {"id": "dbpurchaseplan", "label": "DbPurchasePlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L112"}, {"id": "services_pl_dibang_bridge_service_create_db_plan", "label": "_create_db_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L141"}, {"id": "services_pl_dibang_bridge_service_create_db_inventory", "label": "_create_db_inventory()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L182"}, {"id": "dbinboundoutbound", "label": "DbInboundOutbound", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L182"}, {"id": "services_pl_dibang_bridge_service_inventory_has_weighing_slip", "label": "_inventory_has_weighing_slip()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L225"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L225"}, {"id": "services_pl_dibang_bridge_service_revoke_regeneratable_dibang_for_transport", "label": "revoke_regeneratable_dibang_for_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/serviceLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L47"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L47"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L47"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L72"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L77"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L86"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L86"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L107"}, {"id": "pl_plan_count_plans_by_contract", "label": "count_plans_by_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L171"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L200"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L200"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L200"}, {"id": "pl_plan_create_plan_full", "label": "create_plan_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L279"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L279"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L279"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L381"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L381"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L490"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L519"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L519"}, {"id": "pl_plan_patch_plan_product_certs", "label": "patch_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L581"}, {"id": "planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L34"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L34"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L34"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L59"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L68"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L77"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L77"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L98"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L98"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L98"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L98"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L98"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L167"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L167"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L167"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L259"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L259"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L361"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L361"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L390"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L390"}, {"id": "pl_plan_cancel_plan", "label": "cancel_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L457"}, {"id": "pl_plan_archive_plan", "label": "archive_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L481"}, {"id": "pl_plan_rationale_35", "label": "\u751f\u6210\u8ba1\u5212\u7f16\u53f7 SXDDHYYYYMMDD######", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L35"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_bacLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_transport_py", "label": "transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L1"}, {"id": "pl_transport_generate_transport_no", "label": "_generate_transport_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L45"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L45"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L45"}, {"id": "pl_transport_get_vehicle_info", "label": "_get_vehicle_info()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L69"}, {"id": "pl_transport_ensure_driver_access_token", "label": "_ensure_driver_access_token()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L90"}, {"id": "pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L90"}, {"id": "pl_transport_build_driver_url", "label": "_build_driver_url()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L98"}, {"id": "pl_transport_build_arrange_result", "label": "_build_arrange_result()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L103"}, {"id": "transportinventorylinkread", "label": "TransportInventoryLinkRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L103"}, {"id": "transportarrangeresult", "label": "TransportArrangeResult", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L103"}, {"id": "pl_transport_list_transports", "label": "list_transports()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L121"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L121"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L121"}, {"id": "transportlistresponse", "label": "TransportListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L121"}, {"id": "pl_transport_create_transport", "label": "create_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L176"}, {"id": "transportcreate", "label": "TransportCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L176"}, {"id": "transportread", "label": "TransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L176"}, {"id": "pl_transport_arrange_transport", "label": "arrange_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L248"}, {"id": "transportarrange", "label": "TransportArrange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L248"}, {"id": "pl_transport_get_transport", "label": "get_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L425"}, {"id": "pl_transport_qrcoderesponse", "label": "QrCodeResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L440"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_transport_generate_qrcode", "label": "generate_qrcode()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L450"}, {"id": "pl_transport_transport_scan_feedback", "label": "transport_scan_feedback()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L483"}, {"id": "transportfeedback", "label": "TransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00cLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_reimburseservice", "label": "ReimburseService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L37"}, {"id": "bx_reimburse_reimburseservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L39"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L39"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L39"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L39"}, {"id": "bx_reimburse_reimburseservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L43"}, {"id": "bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L43"}, {"id": "bx_reimburse_reimburseservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L47"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L47"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L47"}, {"id": "bx_reimburse_reimburseservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L57"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L57"}, {"id": "bx_reimburse_reimburseservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L64"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L64"}, {"id": "bx_reimburse_reimburseservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L77"}, {"id": "bx_reimburse_reimburseservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L133"}, {"id": "bx_reimburse_reimburseservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L181"}, {"id": "bx_reimburse_reimburseservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L198"}, {"id": "bx_reimburse_reimburseservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L243"}, {"id": "bx_reimburse_reimburseservice_approval_record_dict", "label": "._approval_record_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L280"}, {"id": "bxreimburseapproval", "label": "BxReimburseApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L280"}, {"id": "bx_reimburse_reimburseservice_latest_approval_per_node", "label": "._latest_approval_per_node()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L293"}, {"id": "bx_reimburse_reimburseservice_query_approvals", "label": "._query_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L310"}, {"id": "bx_reimburse_reimburseservice_get_approvLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_codegen_py", "label": "bx_codegen.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L1"}, {"id": "utils_bx_codegen_generate_apply_code", "label": "generate_apply_code()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L15"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L15"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L15"}, {"id": "utils_bx_codegen_parse_reimburse_date", "label": "parse_reimburse_date()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L40"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L40"}, {"id": "datetime", "label": "datetime", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L40"}, {"id": "utils_bx_codegen_format_reimburse_title", "label": "format_reimburse_title()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L53"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L53"}, {"id": "utils_bx_codegen_is_auto_reimburse_title", "label": "is_auto_reimburse_title()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L57"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L57"}, {"id": "utils_bx_codegen_preview_reimburse_title_seq", "label": "preview_reimburse_title_seq()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L61"}, {"id": "utils_bx_codegen_allocate_reimburse_title_seq", "label": "allocate_reimburse_title_seq()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L76"}, {"id": "utils_bx_codegen_generate_title", "label": "generate_title()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L95"}, {"id": "utils_bx_codegen_resolve_reimburse_title", "label": "resolve_reimburse_title()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L107"}, {"id": "utils_bx_codegen_rationale_1", "label": "\u62a5\u9500\u5355\u53f7/\u6807\u9898\u751f\u6210\uff08\u4ece bx-backend \u8fc1\u79fb\uff0c\u589e\u52a0 tenant_no \u9694\u79bb\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L1"}, {"id": "utils_bx_codegen_rationale_16", "label": "\u751f\u6210\u987a\u5e8f\u5355\u53f7\uff1a{prefix}{YYYYMMDD}{3\u4f4d\u5e8f\u53f7}\u3002 prefix \u793a\u4f8b\uff1aBYJ\uff08\u5907\u7528\u91d1\uff09\u3001BX\uff08\u62a5\u9500\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L16"}, {"id": "utils_bx_codegen_rationale_77", "label": "\u5206\u914d\u540c\u79df\u6237\u3001\u540c\u62a5\u9500\u65e5\u671f\u4e0b\u7684\u6807\u9898\u5e8f\u53f7\uff08MAX+1\uff09\u3002 \u914d\u5408 uk_tenant_reimburse_date_title_seq \u552f\u4e00\u7ea6\u675f\uff0c\u5e76\u53d1\u51b2\u7a81\u65f6\u7531\u4e0a", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L77"}, {"id": "utils_bx_codegen_rationale_101", "label": "\u9884\u89c8\u7528\u6807\u9898\u751f\u6210\uff08\u63d0\u4ea4\u65f6\u4ecd\u4f1a\u5728\u670d\u52a1\u7aef\u91cd\u65b0\u5206\u914d\u5e8f\u53f7\u4ee5\u4fdd\u8bc1\u5e76\u53d1\u5b89\u5168\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L101"}, {"id": "utils_bx_codegen_rationale_114", "label": "\u786e\u5b9a\u6700\u7ec8\u6807\u9898\u4e0e title_seq\u3002 - \u672a\u586b\u6807\u9898\u6216\u4ecd\u4e3a\u81ea\u52a8\u6807\u9898\u683c\u5f0f\u65f6\uff1a\u6309\u62a5\u9500\u65e5\u671f\u91cd\u65b0\u5206\u914d\u5e8f\u53f7\u5e76\u751f\u6210\u6807\u9898\u3002 - \u81ea\u5b9a\u4e49\u6807\u9898\uff1atitle_seq", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_freight_py", "label": "freight.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L1"}, {"id": "pl_freight_generate_settlement_no", "label": "_generate_settlement_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L34"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L34"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L34"}, {"id": "pl_freight_list_settlements", "label": "list_settlements()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "freightsettlementlistresponse", "label": "FreightSettlementListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "pl_freight_create_settlement", "label": "create_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L97"}, {"id": "freightsettlementcreate", "label": "FreightSettlementCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L97"}, {"id": "freightsettlementread", "label": "FreightSettlementRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L97"}, {"id": "pl_freight_get_settlement", "label": "get_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L157"}, {"id": "freightsettlementwithtransports", "label": "FreightSettlementWithTransports", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L157"}, {"id": "pl_freight_update_settlement", "label": "update_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L194"}, {"id": "freightsettlementupdate", "label": "FreightSettlementUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L194"}, {"id": "pl_freight_submit_settlement", "label": "submit_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L219"}, {"id": "pl_freight_approve_settlement", "label": "approve_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L243"}, {"id": "pl_freight_create_voucher", "label": "create_voucher()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L267"}, {"id": "remittancevouchercreate", "label": "RemittanceVoucherCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L267"}, {"id": "remittancevoucherread", "label": "RemittanceVoucherRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L267"}, {"id": "pl_freight_list_vouchers", "label": "list_vouchers()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L296"}, {"id": "plfreightsettlement", "label": "PlFreightSettlement", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L321"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_freight_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_freight_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_plan_service_py", "label": "pl_plan_service.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L1"}, {"id": "services_pl_plan_service_determine_plan_type", "label": "determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L23"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L23"}, {"id": "services_pl_plan_service_product_quantity", "label": "_product_quantity()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "planproductcreate", "label": "PlanProductCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "decimal", "label": "Decimal", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "services_pl_plan_service_sum_product_quantities", "label": "sum_product_quantities()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L41"}, {"id": "services_pl_plan_service_estimate_qty_fields", "label": "_estimate_qty_fields()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L45"}, {"id": "services_pl_plan_service_build_plan_product", "label": "build_plan_product()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "services_pl_plan_service_resolve_driver", "label": "_resolve_driver()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L101"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L101"}, {"id": "services_pl_plan_service_calc_freight_amount", "label": "_calc_freight_amount()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L146"}, {"id": "services_pl_plan_service_validate_toxic_products", "label": "_validate_toxic_products()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L170"}, {"id": "services_pl_plan_service_create_transport_for_plan", "label": "create_transport_for_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L181"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L181"}, {"id": "plantransportcreateblock", "label": "PlanTransportCreateBlock", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L181"}, {"id": "pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L181"}, {"id": "services_pl_plan_service_validate_create_full", "label": "validate_create_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L288"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L288"}, {"id": "services_pl_plan_service_calc_plan_total_amount", "label": "calc_plan_total_amount()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L310"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_plan_service_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "LLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_crud_crm_product_py", "label": "product.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L1"}, {"id": "crm_product_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L19"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L19"}, {"id": "crm_product_category_row_to_dict", "label": "_category_row_to_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L29"}, {"id": "crmproductcategory", "label": "CrmProductCategory", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L29"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L29"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L29"}, {"id": "crm_product_list_categories", "label": "list_categories()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L45"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L45"}, {"id": "crm_product_build_category_tree", "label": "_build_category_tree()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L69"}, {"id": "crm_product_collect_category_with_ancestors", "label": "_collect_category_with_ancestors()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L80"}, {"id": "crm_product_list_category_tree", "label": "list_category_tree()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L96"}, {"id": "crm_product_get_category", "label": "get_category()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L127"}, {"id": "crm_product_create_category", "label": "create_category()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L139"}, {"id": "crm_product_update_category", "label": "update_category()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L176"}, {"id": "crm_product_soft_delete_category", "label": "soft_delete_category()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L211"}, {"id": "crm_product_category_code_exists", "label": "category_code_exists()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L247"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L247"}, {"id": "crm_product_product_row_to_dict", "label": "_product_row_to_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L267"}, {"id": "crmproduct", "label": "CrmProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L267"}, {"id": "crm_product_list_products", "label": "list_products()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L297"}, {"id": "crm_product_get_product", "label": "get_product()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L340"}, {"id": "crm_product_get_product_by_no", "label": "get_product_by_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L352"}, {"id": "crm_product_generate_product_no", "label": "generate_product_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L365"}, {"id": "crm_product_generate_barcode", "label": "generate_barcode()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py", "source_location": "L393"}, {"id": "crm_product_create_product", "label": "create_prLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_inventory_py", "label": "inventory.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L1"}, {"id": "pl_inventory_get_inventory_ledger", "label": "get_inventory_ledger()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "inventoryledgerresponse", "label": "InventoryLedgerResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "pl_inventory_set_warning_threshold", "label": "set_warning_threshold()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L76"}, {"id": "inventorywarningthreshold", "label": "InventoryWarningThreshold", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L76"}, {"id": "pl_inventory_list_warnings", "label": "list_warnings()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L124"}, {"id": "inventorywarningread", "label": "InventoryWarningRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L124"}, {"id": "pl_inventory_update_warning", "label": "update_warning()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L142"}, {"id": "inventorywarningupdate", "label": "InventoryWarningUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L142"}, {"id": "pl_inventory_list_transactions", "label": "list_transactions()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L181"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L181"}, {"id": "inventorytransactionresponse", "label": "InventoryTransactionResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L181"}, {"id": "pl_inventory_get_summary", "label": "get_summary()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L222"}, {"id": "inventorysummaryresponse", "label": "InventorySummaryResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L222"}, {"id": "pl_inventory_list_document_reminders", "label": "list_document_reminders()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L283"}, {"id": "documentreminderread", "label": "DocumentReminderRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L283"}, {"id": "pl_inventory_update_document_reminder", "label": "update_document_reminder()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L301"}, {"id": "documentreminderupdate", "label": "DocumentReminderUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L301"}, {"id": "pl_inventory_check_document_expiry", "label": "check_document_expiry()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L337"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_inventory_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_inventory_py", "Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_pl_models_py", "label": "pl_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L1"}, {"id": "models_pl_models_plcarrier", "label": "PlCarrier", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L28"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_pl_models_plvehicle", "label": "PlVehicle", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L49"}, {"id": "models_pl_models_plpersonnel", "label": "PlPersonnel", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L74"}, {"id": "models_pl_models_plcert", "label": "PlCert", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L96"}, {"id": "models_pl_models_pldriver", "label": "PlDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L121"}, {"id": "models_pl_models_plvehiclepersonnel", "label": "PlVehiclePersonnel", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L147"}, {"id": "models_pl_models_plvehicledriver", "label": "PlVehicleDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L168"}, {"id": "models_pl_models_plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L193"}, {"id": "models_pl_models_plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L276"}, {"id": "models_pl_models_plplanchange", "label": "PlPlanChange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L331"}, {"id": "models_pl_models_pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L358"}, {"id": "models_pl_models_pltransportdblink", "label": "PlTransportDbLink", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L418"}, {"id": "models_pl_models_plplantransport", "label": "PlPlanTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L440"}, {"id": "models_pl_models_pltransportapproval", "label": "PlTransportApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L459"}, {"id": "models_pl_models_plfreightsettlement", "label": "PlFreightSettlement", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L488"}, {"id": "models_pl_models_plfreightsettlementtransport", "label": "PlFreightSettlementTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L519"}, {"id": "models_pl_models_plremittancevoucher", "label": "PlRemittanceVoucher", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L539"}, {"id": "models_pl_models_plinventory", "label": "PlInventory", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L566"}, {"id": "models_pl_models_plinventorytransaction", "label": "PlInventoryTransaction", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L598"}, {"id": "models_pl_models_plinventorywarning", "label": "PlInventoryWarning", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L627"}, {"id": "models_pl_models_pldocumentreminder", "label": "PlDocumentReminder", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L652"}, {"id": "models_pl_models_rationale_122", "label": "\u53f8\u673a\u8868 pl_driver\uff08\u517c\u5bb9\u65e7\u8868\uff0c\u8fc1\u79fb\u540e\u9010\u6b65\u5e9f\u5f03\uff09", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L122"}, {"id": "models_pl_models_rationale_148", "label": "\u8f66\u8f86-\u4eba\u545Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L42"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L42"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L42"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L67"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L72"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L81"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L81"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L102"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L102"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L102"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L102"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L102"}, {"id": "pl_plan_count_plans_by_contract", "label": "count_plans_by_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L166"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L195"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L195"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L195"}, {"id": "pl_plan_create_plan_full", "label": "create_plan_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L274"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L274"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L274"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L373"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L373"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L475"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L504"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L504"}, {"id": "pl_plan_cancel_plan", "label": "cancel_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L571"}, {"id": "pl_plan_archive_plan", "label": "archive_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L595"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_plan_service_py", "label": "pl_plan_service.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L1"}, {"id": "services_pl_plan_service_determine_plan_type", "label": "determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L23"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L23"}, {"id": "services_pl_plan_service_product_quantity", "label": "_product_quantity()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "planproductcreate", "label": "PlanProductCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "decimal", "label": "Decimal", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L31"}, {"id": "services_pl_plan_service_sum_product_quantities", "label": "sum_product_quantities()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L41"}, {"id": "services_pl_plan_service_estimate_qty_fields", "label": "_estimate_qty_fields()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L45"}, {"id": "services_pl_plan_service_build_plan_product", "label": "build_plan_product()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L56"}, {"id": "services_pl_plan_service_resolve_driver", "label": "_resolve_driver()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L101"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L101"}, {"id": "services_pl_plan_service_calc_freight_amount", "label": "_calc_freight_amount()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L146"}, {"id": "services_pl_plan_service_validate_toxic_products", "label": "_validate_toxic_products()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L170"}, {"id": "services_pl_plan_service_resolve_hazard_flags_from_crm", "label": "resolve_hazard_flags_from_crm()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L181"}, {"id": "services_pl_plan_service_update_plan_product_certs", "label": "update_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L208"}, {"id": "services_pl_plan_service_apply_vehicle_prefill_to_plan", "label": "apply_vehicle_prefill_to_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L258"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L258"}, {"id": "plantransportcreateblock", "label": "PlanTransportCreateBlock", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L258"}, {"id": "services_pl_plan_service_create_transport_for_plan", "label": "create_transport_for_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L298"}, {"id": "pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L298"}, {"id": "services_pl_plan_service_validate_create_full", "label": "validate_create_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_plan_service.py", "source_location": "L405"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_planproductbase", "label": "PlanProductBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_plan_planproductcreate", "label": "PlanProductCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L41"}, {"id": "pl_plan_planproductupdate", "label": "PlanProductUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L45"}, {"id": "pl_plan_planproductread", "label": "PlanProductRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L66"}, {"id": "pl_plan_planbase", "label": "PlanBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L80"}, {"id": "pl_plan_plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L116"}, {"id": "pl_plan_planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L122"}, {"id": "pl_plan_planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L151"}, {"id": "pl_plan_planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L174"}, {"id": "pl_plan_createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L183"}, {"id": "pl_plan_plantransportcreateblock", "label": "PlanTransportCreateBlock", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L191"}, {"id": "pl_plan_plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L205"}, {"id": "pl_plan_planlistquery", "label": "PlanListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L216"}, {"id": "pl_plan_planproductcertitem", "label": "PlanProductCertItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L231"}, {"id": "pl_plan_planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L238"}, {"id": "pl_plan_planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L243"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_plan_py", "target": "pl_plan_planproductbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py", "source_location": "L13", "weight": 1.0}, {"source": "plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "label": "public_transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L1"}, {"id": "pl_public_transport_get_transport_by_token", "label": "_get_transport_by_token()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L24"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L24"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L24"}, {"id": "pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L24"}, {"id": "pl_public_transport_parse_feedback_images", "label": "_parse_feedback_images()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L38"}, {"id": "pl_public_transport_format_plan_date", "label": "_format_plan_date()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L50"}, {"id": "pl_public_transport_build_public_page", "label": "_build_public_page()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L60"}, {"id": "publictransportpageread", "label": "PublicTransportPageRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L60"}, {"id": "pl_public_transport_get_public_transport", "label": "get_public_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L115"}, {"id": "pl_public_transport_save_public_feedback", "label": "save_public_feedback()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L122"}, {"id": "publictransportfeedback", "label": "PublicTransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L122"}, {"id": "pl_public_transport_format_file_size", "label": "_format_file_size()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L140"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L140"}, {"id": "pl_public_transport_upload_public_attachment", "label": "upload_public_attachment()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L149"}, {"id": "uploadfile", "label": "UploadFile", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L149"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "json", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "os", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_public_transport_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_sLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_dibang_bridge_service_py", "label": "pl_dibang_bridge_service.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L1"}, {"id": "services_pl_dibang_bridge_service_dibanginventorylinkresult", "label": "DibangInventoryLinkResult", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L27"}, {"id": "services_pl_dibang_bridge_service_resolve_partner_company", "label": "resolve_partner_company()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L36"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L36"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L36"}, {"id": "services_pl_dibang_bridge_service_month_range", "label": "_month_range()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L44"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L44"}, {"id": "services_pl_dibang_bridge_service_plan_type_to_business_type", "label": "_plan_type_to_business_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L51"}, {"id": "services_pl_dibang_bridge_service_product_quantity", "label": "_product_quantity()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L59"}, {"id": "plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L59"}, {"id": "float", "label": "float", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L59"}, {"id": "services_pl_dibang_bridge_service_generate_batch_no", "label": "_generate_batch_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L66"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L66"}, {"id": "services_pl_dibang_bridge_service_ensure_vehicle_exists", "label": "_ensure_vehicle_exists()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L86"}, {"id": "services_pl_dibang_bridge_service_find_monthly_db_plan", "label": "find_monthly_db_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L112"}, {"id": "dbpurchaseplan", "label": "DbPurchasePlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L112"}, {"id": "services_pl_dibang_bridge_service_create_db_plan", "label": "_create_db_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L141"}, {"id": "services_pl_dibang_bridge_service_create_db_inventory", "label": "_create_db_inventory()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L182"}, {"id": "dbinboundoutbound", "label": "DbInboundOutbound", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L182"}, {"id": "services_pl_dibang_bridge_service_sync_dibang_for_transport", "label": "sync_dibang_for_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L221"}, {"id": "pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py", "source_location": "L221"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_dibang_bridge_service_py", "target": "calendar", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "label": "transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L1"}, {"id": "pl_transport_transportbase", "label": "TransportBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_transport_transportcreate", "label": "TransportCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L38"}, {"id": "pl_transport_transportarrange", "label": "TransportArrange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L43"}, {"id": "pl_transport_transportinventorylinkread", "label": "TransportInventoryLinkRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L61"}, {"id": "pl_transport_transportupdate", "label": "TransportUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L71"}, {"id": "pl_transport_transportread", "label": "TransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L95"}, {"id": "pl_transport_transportarrangeresult", "label": "TransportArrangeResult", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L114"}, {"id": "pl_transport_planarrangeinforead", "label": "PlanArrangeInfoRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L123"}, {"id": "pl_transport_transportwithplans", "label": "TransportWithPlans", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L132"}, {"id": "pl_transport_transportfeedback", "label": "TransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L141"}, {"id": "pl_transport_publictransportfeedback", "label": "PublicTransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L150"}, {"id": "pl_transport_publictransportplanproductread", "label": "PublicTransportPlanProductRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L156"}, {"id": "pl_transport_publictransportpageread", "label": "PublicTransportPageRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L165"}, {"id": "pl_transport_approvalsubmit", "label": "ApprovalSubmit", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L187"}, {"id": "pl_transport_approvalrequest", "label": "ApprovalRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L192"}, {"id": "pl_transport_approvalrecordread", "label": "ApprovalRecordRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L198"}, {"id": "pl_transport_transportlistquery", "label": "TransportListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L217"}, {"id": "pl_transport_transportlistresponse", "label": "TransportListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L229"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_filLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_transport_py", "label": "transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L1"}, {"id": "pl_transport_generate_transport_no", "label": "_generate_transport_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L39"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L39"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L39"}, {"id": "pl_transport_get_vehicle_info", "label": "_get_vehicle_info()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L63"}, {"id": "pl_transport_list_transports", "label": "list_transports()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L90"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L90"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L90"}, {"id": "transportlistresponse", "label": "TransportListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L90"}, {"id": "pl_transport_create_transport", "label": "create_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L145"}, {"id": "transportcreate", "label": "TransportCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L145"}, {"id": "transportread", "label": "TransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L145"}, {"id": "pl_transport_arrange_transport", "label": "arrange_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L217"}, {"id": "transportarrange", "label": "TransportArrange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L217"}, {"id": "pl_transport_get_transport", "label": "get_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L331"}, {"id": "pl_transport_qrcoderesponse", "label": "QrCodeResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L346"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_transport_generate_qrcode", "label": "generate_qrcode()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L356"}, {"id": "pl_transport_transport_scan_feedback", "label": "transport_scan_feedback()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L389"}, {"id": "transportfeedback", "label": "TransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L389"}, {"id": "pl_transport_submit_approval", "label": "submit_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L430"}, {"id": "approvalsubmit", "label": "ApprovalSubmit", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L430"}, {"id": "pl_transport_process_approval", "label": "process_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L475"}, {"id": "approvalrequest", "label": "ApprovalRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L475"}, {"id": "approvalrecordread", "label": "ApprovalRecordRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L475"}, {"id": "pl_transport_get_transport_approvals", "label": "get_transport_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_pl_models_py", "label": "pl_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L1"}, {"id": "models_pl_models_plcarrier", "label": "PlCarrier", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L28"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_pl_models_plvehicle", "label": "PlVehicle", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L49"}, {"id": "models_pl_models_plpersonnel", "label": "PlPersonnel", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L74"}, {"id": "models_pl_models_plcert", "label": "PlCert", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L96"}, {"id": "models_pl_models_pldriver", "label": "PlDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L121"}, {"id": "models_pl_models_plvehiclepersonnel", "label": "PlVehiclePersonnel", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L147"}, {"id": "models_pl_models_plvehicledriver", "label": "PlVehicleDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L168"}, {"id": "models_pl_models_plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L193"}, {"id": "models_pl_models_plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L276"}, {"id": "models_pl_models_plplanchange", "label": "PlPlanChange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L330"}, {"id": "models_pl_models_pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L357"}, {"id": "models_pl_models_pltransportdblink", "label": "PlTransportDbLink", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L417"}, {"id": "models_pl_models_plplantransport", "label": "PlPlanTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L439"}, {"id": "models_pl_models_pltransportapproval", "label": "PlTransportApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L458"}, {"id": "models_pl_models_plfreightsettlement", "label": "PlFreightSettlement", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L487"}, {"id": "models_pl_models_plfreightsettlementtransport", "label": "PlFreightSettlementTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L518"}, {"id": "models_pl_models_plremittancevoucher", "label": "PlRemittanceVoucher", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L538"}, {"id": "models_pl_models_plinventory", "label": "PlInventory", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L565"}, {"id": "models_pl_models_plinventorytransaction", "label": "PlInventoryTransaction", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L597"}, {"id": "models_pl_models_plinventorywarning", "label": "PlInventoryWarning", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L626"}, {"id": "models_pl_models_pldocumentreminder", "label": "PlDocumentReminder", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L651"}, {"id": "models_pl_models_rationale_122", "label": "\u53f8\u673a\u8868 pl_driver\uff08\u517c\u5bb9\u65e7\u8868\uff0c\u8fc1\u79fb\u540e\u9010\u6b65\u5e9f\u5f03\uff09", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L122"}, {"id": "models_pl_models_rationale_148", "label": "\u8f66\u8f86-\u4eba\u545Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L48"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L48"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L48"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L70"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L75"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L84"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L84"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L105"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L105"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L105"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L105"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L105"}, {"id": "pl_plan_count_plans_by_contract", "label": "count_plans_by_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L204"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L233"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L233"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L233"}, {"id": "pl_plan_create_plan_full", "label": "create_plan_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L312"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L312"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L312"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L414"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L414"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L523"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L566"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L566"}, {"id": "pl_plan_patch_plan_product_certs", "label": "patch_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L628"}, {"id": "planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "label": "check_pl_json_aliases.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L1"}, {"id": "scripts_check_pl_json_aliases_snake_to_camel", "label": "snake_to_camel()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L43"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L43"}, {"id": "scripts_check_pl_json_aliases_iter_field_assignments", "label": "iter_field_assignments()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L48"}, {"id": "ast", "label": "AST", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L48"}, {"id": "scripts_check_pl_json_aliases_field_has_alias", "label": "field_has_alias()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L61"}, {"id": "expr", "label": "expr", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L61"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L61"}, {"id": "scripts_check_pl_json_aliases_main", "label": "main()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L71"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L71"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "ast", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "re", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L10", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "sys", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L11", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "pathlib", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L12", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "scripts_check_pl_json_aliases_snake_to_camel", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L43", "weight": 1.0}, {"source": "scripts_check_pl_json_aliases_snake_to_camel", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L43", "weight": 1.0}, {"source": "scripts_check_pl_json_aliases_snake_to_camel", "target": "str", "relation": "references", "context": "return_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L43", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "scripts_check_pl_json_aliases_iter_field_assignments", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L48", "weight": 1.0}, {"source": "scripts_check_pl_json_aliases_iter_field_assignments", "target": "ast", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L48", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "scripts_check_pl_json_aliaLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "label": "common.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L1"}, {"id": "bx_common_dt_to_str", "label": "_dt_to_str()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11"}, {"id": "datetime", "label": "datetime", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11"}, {"id": "bx_common_date_to_str", "label": "_date_to_str()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L17"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L17"}, {"id": "bx_common_pagedquery", "label": "PagedQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L29"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_common_apiresponse", "label": "ApiResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L36"}, {"id": "bx_common_pageddata", "label": "PagedData", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L42"}, {"id": "bx_common_pagedresponse", "label": "PagedResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L51"}, {"id": "bx_common_rationale_1", "label": "bx \u539f\u7cfb\u7edf API \u54cd\u5e94\u5305\u88c5\uff08code=0 / msg / data.rows\uff09\uff0c\u4e0e\u95e8\u6237 success_response \u5206\u79bb\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "pydantic_alias_generators", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "bx_common_dt_to_str", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11", "weight": 1.0}, {"source": "bx_common_dt_to_str", "target": "datetime", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11", "weight": 1.0}, {"source": "bx_common_dt_to_str", "target": "str", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "bx_common_date_to_str", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L17", "weight": 1.0}, {"source": "bx_common_date_to_str", "target": "date", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L17", "weight": 1.0}, {"source": "bx_common_date_to_str", "target": "str", "relLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_transport_py", "label": "transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L1"}, {"id": "pl_transport_generate_transport_no", "label": "_generate_transport_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L46"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L46"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L46"}, {"id": "pl_transport_resolve_driver_info", "label": "_resolve_driver_info()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L70"}, {"id": "pl_transport_get_vehicle_info", "label": "_get_vehicle_info()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L106"}, {"id": "pl_transport_ensure_driver_access_token", "label": "_ensure_driver_access_token()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L156"}, {"id": "pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L156"}, {"id": "pl_transport_build_driver_url", "label": "_build_driver_url()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L164"}, {"id": "pl_transport_build_arrange_result", "label": "_build_arrange_result()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L169"}, {"id": "transportinventorylinkread", "label": "TransportInventoryLinkRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L169"}, {"id": "transportarrangeresult", "label": "TransportArrangeResult", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L169"}, {"id": "pl_transport_list_transports", "label": "list_transports()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L187"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L187"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L187"}, {"id": "transportlistresponse", "label": "TransportListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L187"}, {"id": "pl_transport_create_transport", "label": "create_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L242"}, {"id": "transportcreate", "label": "TransportCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L242"}, {"id": "transportread", "label": "TransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L242"}, {"id": "pl_transport_arrange_transport", "label": "arrange_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L314"}, {"id": "transportarrange", "label": "TransportArrange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L314"}, {"id": "pl_transport_get_transport", "label": "get_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L491"}, {"id": "pl_transport_qrcoderesponse", "label": "QrCodeResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L506"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_transport_generate_qrcode", "label": "generate_qrcode()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py", "source_location": "L516"}, {"id": "pl_transport_transport_scan_feedback", "label": "transport_scan_feedback()", "file_type": "code", "source_file"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_inventory_py", "label": "inventory.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L1"}, {"id": "pl_inventory_get_inventory_ledger", "label": "get_inventory_ledger()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "inventoryledgerresponse", "label": "InventoryLedgerResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L47"}, {"id": "pl_inventory_set_warning_threshold", "label": "set_warning_threshold()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L76"}, {"id": "inventorywarningthreshold", "label": "InventoryWarningThreshold", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L76"}, {"id": "pl_inventory_list_warnings", "label": "list_warnings()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L124"}, {"id": "inventorywarningread", "label": "InventoryWarningRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L124"}, {"id": "pl_inventory_update_warning", "label": "update_warning()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L142"}, {"id": "inventorywarningupdate", "label": "InventoryWarningUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L142"}, {"id": "pl_inventory_list_transactions", "label": "list_transactions()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L181"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L181"}, {"id": "inventorytransactionresponse", "label": "InventoryTransactionResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L181"}, {"id": "pl_inventory_get_summary", "label": "get_summary()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L222"}, {"id": "inventorysummaryresponse", "label": "InventorySummaryResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L222"}, {"id": "pl_inventory_list_document_reminders", "label": "list_document_reminders()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L283"}, {"id": "documentreminderread", "label": "DocumentReminderRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L283"}, {"id": "pl_inventory_update_document_reminder", "label": "update_document_reminder()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L301"}, {"id": "documentreminderupdate", "label": "DocumentReminderUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L301"}, {"id": "pl_inventory_check_document_expiry", "label": "check_document_expiry()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L341"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_inventory_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/inventory.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_inventory_py", "Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "label": "check_pl_json_aliases.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L1"}, {"id": "scripts_check_pl_json_aliases_snake_to_camel", "label": "snake_to_camel()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L43"}, {"id": "scripts_check_pl_json_aliases_iter_field_assignments", "label": "iter_field_assignments()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L48"}, {"id": "scripts_check_pl_json_aliases_field_has_alias", "label": "field_has_alias()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L61"}, {"id": "scripts_check_pl_json_aliases_main", "label": "main()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L71"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "ast", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "re", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L10", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "sys", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L11", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "pathlib", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L12", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "scripts_check_pl_json_aliases_snake_to_camel", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L43", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "scripts_check_pl_json_aliases_iter_field_assignments", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L48", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "scripts_check_pl_json_aliases_field_has_alias", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L61", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_scripts_check_pl_json_aliases_py", "target": "scripts_check_pl_json_aliases_main", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L71", "weight": 1.0}, {"source": "scripts_check_pl_json_aliases_main", "target": "scripts_check_pl_json_aliases_iter_field_assignments", "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L82", "weight": 1.0}, {"source": "scripts_check_pl_json_aliases_main", "target": "scripts_check_pl_json_aliases_field_has_alias", "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L87", "weight": 1.0}, {"source": "scripts_check_pl_json_aliases_main", "target": "scripts_check_pl_json_aliases_snake_to_camel", "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L88", "weight": 1.0}], "raw_calls": [{"caller_nid": "scripts_check_pl_json_aliases_snake_to_camel", "callee": "split", "is_member_call": true, "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/scripts/check_pl_json_aliases.py", "source_location": "L44"}, {"caller_nid": "scripts_check_pl_jsonLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_init_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_init_py", "target": "app_api_pl", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_init_py", "target": "app_api_pl", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/__init__.py", "source_location": "L5", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_base_data_py", "label": "base_data.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L1"}, {"id": "pl_base_data_carrierbase", "label": "CarrierBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_base_data_carriercreate", "label": "CarrierCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L22"}, {"id": "pl_base_data_carrierupdate", "label": "CarrierUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L26"}, {"id": "pl_base_data_carrierread", "label": "CarrierRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L35"}, {"id": "pl_base_data_vehiclepersonnelrow", "label": "VehiclePersonnelRow", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L53"}, {"id": "pl_base_data_certrow", "label": "CertRow", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L64"}, {"id": "pl_base_data_certread", "label": "CertRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L74"}, {"id": "pl_base_data_vehiclebase", "label": "VehicleBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L90"}, {"id": "pl_base_data_vehiclecreate", "label": "VehicleCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L102"}, {"id": "pl_base_data_vehicleupdate", "label": "VehicleUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L108"}, {"id": "pl_base_data_vehicleread", "label": "VehicleRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L121"}, {"id": "pl_base_data_vehicledetailread", "label": "VehicleDetailRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L135"}, {"id": "pl_base_data_personnelbase", "label": "PersonnelBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L146"}, {"id": "pl_base_data_personnelcreate", "label": "PersonnelCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L155"}, {"id": "pl_base_data_personnelupdate", "label": "PersonnelUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L160"}, {"id": "pl_base_data_personnelread", "label": "PersonnelRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L171"}, {"id": "pl_base_data_personneldetailread", "label": "PersonnelDetailRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L185"}, {"id": "pl_base_data_driverbase", "label": "DriverBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L195"}, {"id": "pl_base_data_drivercreate", "label": "DriverCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L208"}, {"id": "pl_base_data_driverupdate", "label": "DriverUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L212"}, {"id": "pl_base_data_driverread", "label": "DriverRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L226"}, {"id": "pl_base_data_vehicledrivercreate", "label": "VehicleDriverCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L244"}, {"id": "pl_base_data_vehicledriverread", "label": "VehicleDriverRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py", "source_location": "L251"}, {"id": "pl_base_dataLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L48"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L48"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L48"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L73"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L78"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L87"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L87"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L108"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L108"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L108"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L108"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L108"}, {"id": "pl_plan_count_plans_by_contract", "label": "count_plans_by_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L172"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L201"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L201"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L201"}, {"id": "pl_plan_create_plan_full", "label": "create_plan_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L280"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L280"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L280"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L382"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L382"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L491"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L534"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L534"}, {"id": "pl_plan_patch_plan_product_certs", "label": "patch_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L596"}, {"id": "planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/plLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_freight_py", "label": "freight.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L1"}, {"id": "pl_freight_generate_settlement_no", "label": "_generate_settlement_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L34"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L34"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L34"}, {"id": "pl_freight_list_settlements", "label": "list_settlements()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "freightsettlementlistresponse", "label": "FreightSettlementListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L64"}, {"id": "pl_freight_create_settlement", "label": "create_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L97"}, {"id": "freightsettlementcreate", "label": "FreightSettlementCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L97"}, {"id": "freightsettlementread", "label": "FreightSettlementRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L97"}, {"id": "pl_freight_get_settlement", "label": "get_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L157"}, {"id": "freightsettlementwithtransports", "label": "FreightSettlementWithTransports", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L157"}, {"id": "pl_freight_update_settlement", "label": "update_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L194"}, {"id": "freightsettlementupdate", "label": "FreightSettlementUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L194"}, {"id": "pl_freight_submit_settlement", "label": "submit_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L219"}, {"id": "pl_freight_approve_settlement", "label": "approve_settlement()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L243"}, {"id": "pl_freight_create_voucher", "label": "create_voucher()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L267"}, {"id": "remittancevouchercreate", "label": "RemittanceVoucherCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L267"}, {"id": "remittancevoucherread", "label": "RemittanceVoucherRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L267"}, {"id": "pl_freight_list_vouchers", "label": "list_vouchers()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L296"}, {"id": "plfreightsettlement", "label": "PlFreightSettlement", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L321"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_freight_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_freight_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/freight.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "label": "transport.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L1"}, {"id": "pl_transport_transportbase", "label": "TransportBase", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_transport_transportcreate", "label": "TransportCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L38"}, {"id": "pl_transport_transportarrange", "label": "TransportArrange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L43"}, {"id": "pl_transport_transportinventorylinkread", "label": "TransportInventoryLinkRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L61"}, {"id": "pl_transport_transportupdate", "label": "TransportUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L71"}, {"id": "pl_transport_transportread", "label": "TransportRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L95"}, {"id": "pl_transport_transportarrangeresult", "label": "TransportArrangeResult", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L114"}, {"id": "pl_transport_transportwithplans", "label": "TransportWithPlans", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L123"}, {"id": "pl_transport_transportfeedback", "label": "TransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L132"}, {"id": "pl_transport_publictransportfeedback", "label": "PublicTransportFeedback", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L141"}, {"id": "pl_transport_publictransportplanproductread", "label": "PublicTransportPlanProductRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L147"}, {"id": "pl_transport_publictransportpageread", "label": "PublicTransportPageRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L155"}, {"id": "pl_transport_approvalsubmit", "label": "ApprovalSubmit", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L176"}, {"id": "pl_transport_approvalrequest", "label": "ApprovalRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L181"}, {"id": "pl_transport_approvalrecordread", "label": "ApprovalRecordRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L187"}, {"id": "pl_transport_transportlistquery", "label": "TransportListQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L206"}, {"id": "pl_transport_transportlistresponse", "label": "TransportListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L218"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/transport.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_transport_py", "target": Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "label": "inventory.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L1"}, {"id": "pl_inventory_inventoryread", "label": "InventoryRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L14"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "pl_inventory_inventorytransactionread", "label": "InventoryTransactionRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L36"}, {"id": "pl_inventory_inventorywarningread", "label": "InventoryWarningRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L57"}, {"id": "pl_inventory_inventorywarningupdate", "label": "InventoryWarningUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L72"}, {"id": "pl_inventory_inventorywarningthreshold", "label": "InventoryWarningThreshold", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L78"}, {"id": "pl_inventory_documentreminderread", "label": "DocumentReminderRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L90"}, {"id": "pl_inventory_documentreminderupdate", "label": "DocumentReminderUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L108"}, {"id": "pl_inventory_inventoryledgerquery", "label": "InventoryLedgerQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L119"}, {"id": "pl_inventory_inventoryledgerresponse", "label": "InventoryLedgerResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L126"}, {"id": "pl_inventory_inventorytransactionquery", "label": "InventoryTransactionQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L131"}, {"id": "pl_inventory_inventorytransactionresponse", "label": "InventoryTransactionResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L141"}, {"id": "pl_inventory_inventorysummaryquery", "label": "InventorySummaryQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L146"}, {"id": "pl_inventory_inventorysummaryitem", "label": "InventorySummaryItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L154"}, {"id": "pl_inventory_inventorysummaryresponse", "label": "InventorySummaryResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L163"}, {"id": "pl_inventory_transportstatsquery", "label": "TransportStatsQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L167"}, {"id": "pl_inventory_transportstatsitem", "label": "TransportStatsItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L174"}, {"id": "pl_inventory_transportstatsresponse", "label": "TransportStatsResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L181"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "target": "decimal", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_pl_inventory_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/inventory.py", "source_location": "L4", "weight": 1.Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L43"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L43"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L43"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L68"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L73"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L82"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L82"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L103"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L103"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L103"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L103"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L103"}, {"id": "pl_plan_count_plans_by_contract", "label": "count_plans_by_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L167"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L196"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L196"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L196"}, {"id": "pl_plan_create_plan_full", "label": "create_plan_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L275"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L275"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L275"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L374"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L374"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L476"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L505"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L505"}, {"id": "pl_plan_cancel_plan", "label": "cancel_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L572"}, {"id": "pl_plan_archive_plan", "label": "archive_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L596"Line truncated
Loaded 100 of 328 files, more files were not shown because too many files have changed in this diff. Show more