Kaynağa Gözat

feat(backend): gate archive writes and mask plan prices by menu code

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 1 ay önce
ebeveyn
işleme
b47c809300
1 değiştirilmiş dosya ile 18 ekleme ve 1 silme
  1. 18 1
      backend/app/api/pl/plan.py

+ 18 - 1
backend/app/api/pl/plan.py

@@ -102,6 +102,11 @@ from app.services.pl_plan_archive_stop_service import (
     sync_plan_products_from_stop_archive,
 )
 from app.services.pl_plan_archive_export import build_plan_archive_export_rows
+from app.services.pl_plan_price_mask import (
+    mask_plan_with_products_prices,
+    user_can_archive_plan,
+    user_can_view_archive_prices,
+)
 from app.services.pl_plan_list_attachments import load_plan_document_attachments_by_plan_ids
 from app.services.pl_plan_print_service import get_delivery_slip_print_context
 from app.services.pl_plan_stop_service import (
@@ -529,6 +534,7 @@ def list_plans(
         plan_ids=plan_ids,
     )
     stops_by_plan = load_plan_stops_grouped(db, tenant_no, plan_ids)
+    can_price = user_can_view_archive_prices(db, user)
 
     result_list: list[PlanWithProducts] = []
     for plan in plans:
@@ -583,6 +589,7 @@ def list_plans(
             plan,
             stops_by_plan.get(plan.id, (None, [])),
         )
+        plan_item = mask_plan_with_products_prices(plan_item, enabled=not can_price)
         result_list.append(plan_item)
 
     return PlanListResponse(total=total, list=result_list)
@@ -740,6 +747,8 @@ def export_plans(
             transports_by_id = _load_transports_by_id(db, tenant_no, transport_ids)
             items = build_plan_archive_export_rows(db, tenant_no, plans, transports_by_id)
             cols = filter_export_columns(PLAN_ARCHIVE_EXPORT_COLUMNS, body.columns)
+            if not user_can_view_archive_prices(db, user):
+                cols = [c for c in cols if c.field not in ARCHIVE_PRICE_EXPORT_FIELDS]
             sheet_title = "计划归档"
             filename_stem = f"计划归档_{date_str}"
         else:
@@ -1474,7 +1483,8 @@ def get_plan(
     result.demander_contracts = demander_contracts
     stops = load_plan_stops_grouped(db, tenant_no, [id]).get(id, (None, []))
     attach_plan_stops_to_item(result, plan, stops)
-    return result
+    can_price = user_can_view_archive_prices(db, user)
+    return mask_plan_with_products_prices(result, enabled=not can_price)
 
 
 # =============================================================================
@@ -2040,6 +2050,9 @@ def cancel_plan_wait_notice(
 
 
 FORCE_FOLLOW_STATUS_PERM = "pl:plan:force-follow-status"
+ARCHIVE_PRICE_EXPORT_FIELDS = frozenset(
+    {"unitPrice", "amount", "freightPrice", "freightAmount"}
+)
 ALLOWED_FORCE_FOLLOW_STATUSES = frozenset(
     {"drafting", "wait_notice", "pending_arrange", "arranged", "completed", "cancelled"}
 )
@@ -2150,6 +2163,8 @@ def archive_plan_draft(
     user: DbUserContext = Depends(get_db_current_user),
 ) -> PlanWithProducts:
     """暂存归档填写内容:不改库存、不标已归档。"""
+    if not user_can_archive_plan(db, user):
+        raise HTTPException(status_code=403, detail="无运输计划归档操作权限")
     tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
     plan = _get_plan(db, tenant_no, id, user)
 
@@ -2228,6 +2243,8 @@ def archive_plan(
     db: Session = Depends(get_db),
     user: DbUserContext = Depends(get_db_current_user),
 ) -> PlanWithProducts:
+    if not user_can_archive_plan(db, user):
+        raise HTTPException(status_code=403, detail="无运输计划归档操作权限")
     tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
     plan = _get_plan(db, tenant_no, id, user)