Files
cma-management/backend/app/api/subjects.py
T
Hermes CI Fix fb4609be14
ci/woodpecker/push/main Pipeline failed
feat(entity-dim): 账套维度收口批 — subjects/analysis_results 加列 + 分析结论账套化 + 模板实例化构造点补账套
- ① kpi_templates instantiate 构造点显式传会话账套(原缺 entity_id ⇒ 静默落 e1),kpi_code 判重按账套收紧
- ② kpi_subject_map 3 个读取点加护栏注释(不加列、不改语义)
- ③ subjects 分层:读口 union(NULL=全局标准准则科目 / N=账套私有),UPSERT 唯一键改 (entity_id, subject_code)
- ④ analysis_results 账套化:读/写/删三端点按会话账套判定归属(列未落地时 kpi_code JOIN 止血),
     无归属行进 unattributed 登记、删除一律 404
- 模型层按现网 DDL 补齐:KPIDefinition(template_id/is_system + uk_entity_kpi)、AnalysisResult.entity_id、Subject.entity_id
- 新增 migrate_{subjects,analysis_results}_entity_id_20260923.py(--check/--apply/--down)、
  22 条对账用例 test_entity_dimension_convergence_20260923.py

DDL 已由 ops 受控通道落地(subjects 21:31:56 / analysis_results 21:31:59 CST,审批 1e9b4d9a/5ffb1640)
本提交为切片提交,未 push(发布须另取放行)
2026-09-23 21:39:24 +08:00

107 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""会计科目管理 — 新30号准则适配"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import func
from typing import Optional, List
from app.database import get_db
from app.auth_middleware import require_role
from app.deps import get_entity_id
from app.models import Subject
import logging
logger = logging.getLogger("cma.subjects")
router = APIRouter(prefix="/api/cma/subjects", tags=["会计科目"],
dependencies=[Depends(require_role("ceo", "finance", "business"))],
)
@router.get("")
def list_subjects(
category: Optional[str] = Query(None, description="新30号准则分类过滤"),
keyword: Optional[str] = Query(None, description="科目名称/编码搜索"),
db: Session = Depends(get_db),
entity_id: int = Depends(get_entity_id),
):
"""科目列表 — 支持新30号准则分类筛选
账套分层(2026-09-23 `subjects` 加 `entity_id` 列):返回**全局标准准则科目**
(`entity_id IS NULL`)∪ **本账套私有明细**(`entity_id = 会话账套`)。
行为变更(预期):博海会话不再看到酣客智享通明细(`100106 酒窖备用金` / `100108 友赞商户` 等)。
返回体字段不删不加必填(前端契约不变)。
"""
query = db.query(Subject).filter(
Subject.is_active == 1,
(Subject.entity_id.is_(None)) | (Subject.entity_id == entity_id), # 分层读取口径
)
if category:
query = query.filter(Subject.new_standard_category == category)
if keyword:
like = f"%{keyword}%"
query = query.filter(
Subject.subject_name.like(like) | Subject.subject_code.like(like)
)
subjects = query.order_by(Subject.subject_code).all()
return {
"total": len(subjects),
"data": [
{
"id": s.id,
"subject_code": s.subject_code,
"subject_name": s.subject_name,
"parent_code": s.parent_code,
"level": s.level,
"category": s.category,
"new_standard_category": s.new_standard_category,
"is_active": s.is_active,
"remark": s.remark,
"updated_at": s.updated_at.isoformat() if s.updated_at else None,
}
for s in subjects
],
}
@router.put("/{subject_id}")
def update_subject_category(
subject_id: int,
new_standard_category: str = Query(..., description="operating/investing/financing/tax/discontinued"),
db: Session = Depends(get_db),
):
"""更新单个科目的新30号准则分类"""
subject = db.query(Subject).filter(Subject.id == subject_id).first()
if not subject:
raise HTTPException(status_code=404, detail="科目不存在")
valid = {"operating", "operating_rd", "operating_fx", "investing",
"financing", "financing_fx", "tax", "discontinued"}
if new_standard_category not in valid:
raise HTTPException(status_code=400, detail=f"无效的分类: {new_standard_category}")
subject.new_standard_category = new_standard_category
db.commit()
return {"message": "更新成功", "subject_id": subject_id, "new_standard_category": new_standard_category}
@router.put("/batch/category")
def batch_update_category(
ids: List[int] = Query(..., description="科目ID列表"),
new_standard_category: str = Query(..., description="operating/investing/financing/tax/discontinued"),
db: Session = Depends(get_db),
):
"""批量更新科目新30号准则分类"""
valid = {"operating", "operating_rd", "operating_fx", "investing",
"financing", "financing_fx", "tax", "discontinued"}
if new_standard_category not in valid:
raise HTTPException(status_code=400, detail=f"无效的分类: {new_standard_category}")
updated = db.query(Subject).filter(
Subject.id.in_(ids), Subject.is_active == 1
).update({"new_standard_category": new_standard_category}, synchronize_session=False)
db.commit()
return {"message": f"批量更新成功", "updated_count": updated}