feat(cma): audit write-side entity closure + entity-dimension data dictionary
task dama-entity-isolation-sweep-20260923 (sections 2-2 4/5, merged by projectBot 2026-09-23 18:2x)
4) operation_logs write side: every audit write carries the account (no DDL, no column added)
- new app/utils/oplog.py::log_op() single wrapper: sets detail.entity_id; scope=global for
by-design non-entity writes (platform dict / role-level); scope=batch + OPLOG_BATCH_NO_ENTITY
sentinel for cross-account batches; no context -> OPLOG_NO_ENTITY sentinel (never guess)
- 16 remaining construction points converted (data/alert_rules/bi_reports/kpi_causality/
bot_bridge x2/budget_generate/driver_budget/kpis _log x3/templates _log x2/erp_sync);
pre-4 state had 20 sites without entity_id, now 0 outside the wrapper
- read side untouched (knowledge_service still user_id fallback); history not backfilled
5) docs/entity-dimension-data-dictionary.md: 8-table three-state registry
(kpi_templates/driver_factor_templates/scenario_suggestions/bot_bridge_config = non-entity;
kpi_subject_map = inherited via kpi_id; analysis_results/subjects = account dimension,
legacy rows still NULL -> other task; operation_logs = non-entity column + detail.entity_id)
Evidence: RED 2 failed/7 passed (reverted call sites) -> GREEN full 1428 passed; 9 new tests
including two read-back rows; app md5 restore verified identical; no cross-account writes
LOCAL commit only - push is gated (ahead contains the P1 entity-dim batch commit fb4609b)
This commit is contained in:
@@ -10,6 +10,7 @@ from app.database import get_db
|
||||
from app.deps import get_entity_id
|
||||
from app.auth_middleware import require_auth, require_role
|
||||
from app.models import SystemConfig, OperationLog
|
||||
from app.utils.oplog import log_op
|
||||
from app.models.driver_budget import DriverFactorTemplate, DriverFactorBudget
|
||||
|
||||
router = APIRouter(
|
||||
@@ -126,6 +127,7 @@ def set_driver_mode(
|
||||
data: dict,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(require_auth),
|
||||
entity_id: int = Depends(get_entity_id),
|
||||
):
|
||||
"""切换预算编制模式: subject(科目模式) / driver(驱动因子模式)"""
|
||||
mode = data.get("mode", "subject")
|
||||
@@ -145,13 +147,11 @@ def set_driver_mode(
|
||||
db.add(cfg)
|
||||
db.commit()
|
||||
|
||||
log = OperationLog(
|
||||
action="update",
|
||||
target_type="budget",
|
||||
target_id=0,
|
||||
detail=json.dumps({"mode": mode, "action": "切换编制模式"}, ensure_ascii=False),
|
||||
)
|
||||
db.add(log)
|
||||
# 2026-09-23 ④:审计带账套(会话账套)+ 显式标注该键当前仍是**全局键**
|
||||
#(budget_driver_mode 拆账套 = 另单排期项,见 dama-entity-isolation-sweep-20260923 §二之三)
|
||||
log_op(db, "update", target_type="budget", target_id=0,
|
||||
detail={"mode": mode, "action": "切换编制模式", "entity_scope": "global_key"},
|
||||
entity_id=entity_id)
|
||||
db.commit()
|
||||
|
||||
return {"message": f"已切换为{'驱动因子模式' if mode == 'driver' else '科目模式'}", "mode": mode}
|
||||
@@ -335,6 +335,7 @@ def driver_calculate(
|
||||
target_type="budget",
|
||||
target_id=budget_record.id,
|
||||
detail=json.dumps({
|
||||
"entity_id": entity_id, # 2026-09-23 ④:审计带账套(=会话账套)
|
||||
"name": name,
|
||||
"formula": formula_text,
|
||||
"factors": complete_factors,
|
||||
|
||||
Reference in New Issue
Block a user