Sfoglia il codice sorgente

feat(api): allow withdraw of in-approval vehicle recharge applies

Applicants can return an in-approval apply to draft while keeping prior approval rows.

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 1 mese fa
parent
commit
d8df5c47e2

+ 13 - 0
backend/app/api/pl/vehicle_recharge.py

@@ -336,6 +336,19 @@ def cancel_apply(
     return svc.cancel_apply(db, tenant_no, user, id, mine_vehicles=mine_vehicles)
 
 
+@apply_router.post("/{id}/withdraw", response_model=VehicleRechargeApplyRead)
+def withdraw_apply(
+    id: str,
+    mine_vehicles: bool = Query(default=False, alias="mineVehicles"),
+    db: Session = Depends(get_db),
+    user: DbUserContext = Depends(get_db_current_user),
+) -> VehicleRechargeApplyRead:
+    tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
+    return svc.withdraw_apply(
+        db, tenant_no, user, id, mine_vehicles=mine_vehicles
+    )
+
+
 @apply_router.delete("/{ids}", status_code=status.HTTP_204_NO_CONTENT)
 def delete_applies(
     ids: str,

+ 42 - 4
backend/app/services/pl_vehicle_recharge_service.py

@@ -30,7 +30,10 @@ from app.schemas.pl.vehicle_recharge import (
     VehicleRechargeRecordUpdate,
 )
 from app.services.pl_data_scope import apply_pl_scope, assert_pl_row_in_scope
-from app.services.pl_vehicle_mine_vehicles import license_plates_for_user_personnel
+from app.services.pl_vehicle_mine_vehicles import (
+    license_plates_for_user_personnel,
+    should_restrict_mine_vehicles,
+)
 
 _EDITABLE_STATUSES = frozenset({"draft", "rejected"})
 _BIZ_TYPE_VEHICLE_RECHARGE = "vehicle_recharge"
@@ -135,11 +138,13 @@ def _get_apply_row(
     )
     if not row:
         raise HTTPException(status_code=404, detail="申请单不存在")
-    if mine_vehicles:
+    if should_restrict_mine_vehicles(
+        db, tenant_no, user.id, mine_vehicles=mine_vehicles
+    ):
         plates = license_plates_for_user_personnel(db, tenant_no, user.id)
         if row.license_plate not in plates:
             raise HTTPException(status_code=403, detail="无权查看该申请")
-    else:
+    elif not mine_vehicles:
         assert_pl_row_in_scope(db, row, PlVehicleRechargeApply, user, tenant_no)
     return row
 
@@ -530,11 +535,16 @@ def list_applies(
     if ids:
         query = query.filter(PlVehicleRechargeApply.id.in_(ids))
 
-    if mine_vehicles:
+    if should_restrict_mine_vehicles(
+        db, tenant_no, user.id, mine_vehicles=mine_vehicles
+    ):
         plates = license_plates_for_user_personnel(db, tenant_no, user.id)
         if not plates:
             return [], 0
         query = query.filter(PlVehicleRechargeApply.license_plate.in_(plates))
+    elif mine_vehicles:
+        # 管理员 + mineVehicles:本租户全量,跳过挂靠与数据范围
+        pass
     else:
         query = apply_pl_scope(query, PlVehicleRechargeApply, user, db, tenant_no)
     total = query.count()
@@ -567,6 +577,10 @@ def get_apply(
 def _assert_mine_vehicle_plate(
     db: Session, tenant_no: str, user: DbUserContext, plate: str
 ) -> None:
+    if not should_restrict_mine_vehicles(
+        db, tenant_no, user.id, mine_vehicles=True
+    ):
+        return
     plates = license_plates_for_user_personnel(db, tenant_no, user.id)
     if (plate or "").strip() not in plates:
         raise HTTPException(status_code=403, detail="只能选择本人车辆")
@@ -684,6 +698,30 @@ def cancel_apply(
     return apply_to_read(row, db)
 
 
+def withdraw_apply(
+    db: Session,
+    tenant_no: str,
+    user: DbUserContext,
+    apply_id: str,
+    *,
+    mine_vehicles: bool = False,
+) -> VehicleRechargeApplyRead:
+    row = _get_apply_row(
+        db, tenant_no, apply_id, user, mine_vehicles=mine_vehicles
+    )
+    if (row.applicant_id or "").strip() != (user.id or "").strip():
+        raise HTTPException(status_code=403, detail="仅申请人可撤回")
+    if row.status != "in_approval":
+        raise HTTPException(status_code=400, detail="仅审批中的申请可撤回")
+    row.status = "draft"
+    row.current_node = None
+    row.update_by = user.id
+    row.update_time = datetime.now()
+    db.commit()
+    db.refresh(row)
+    return apply_to_read(row, db, include_detail=True)
+
+
 def submit_apply(
     db: Session,
     tenant_no: str,