Add tenant-scoped teams and projects, order attribution across four businesses, conversion inheritance, scoped statistics and audited reassignment. Reuse existing Web and mobile UI patterns; team regions and hospitals remain informational. Include incremental SQL and isolated regression coverage. Actual MySQL and browser/WebView integration validation remains pending; relates to issue #13.
52 lines
2.2 KiB
Python
52 lines
2.2 KiB
Python
"""Shared attribution boundary for existing business write and read paths."""
|
|
from fastapi import HTTPException
|
|
from app.core.config import settings
|
|
|
|
|
|
def create_assignment(db, tenant_no, user, project_id, biz_type):
|
|
from app.services.project_management import validate_assignment
|
|
if biz_type == 'clinical_application':
|
|
if project_id:
|
|
raise HTTPException(400, '临床应用不支持项目归属')
|
|
return None
|
|
return validate_assignment(db, tenant_no, user, project_id, biz_type,
|
|
required=settings.PROJECT_ASSIGNMENT_REQUIRED)
|
|
|
|
|
|
def guard_project_edit(row, payload):
|
|
"""Omission preserves attribution; explicit changes require audited maintenance."""
|
|
key = 'projectId' if 'projectId' in payload else 'project_id'
|
|
if key in payload and (payload[key] or None) != (row.project_id or None):
|
|
raise HTTPException(400, '请通过项目归属维护调整')
|
|
|
|
|
|
def assignment_brief(db, tenant_no, project_id):
|
|
if not db or not project_id:
|
|
return dict(projectId=project_id, projectName=None, teamId=None, teamName=None)
|
|
from app.services.project_management import project_brief
|
|
return project_brief(db, tenant_no, project_id)
|
|
|
|
|
|
def filter_assignment(query, model, db, tenant_no, project_id=None, team_id=None):
|
|
if project_id:
|
|
query = query.filter(model.project_id == project_id)
|
|
if team_id:
|
|
from app.models.project_management import Project
|
|
projects = db.query(Project.id).filter(Project.tenant_no == tenant_no,
|
|
Project.team_id == team_id, Project.del_flag == 0)
|
|
query = query.filter(model.project_id.in_(projects))
|
|
return query
|
|
|
|
|
|
def accessible_order(db, model, tenant_no, user, record_id, *, lock=False):
|
|
from app.core.data_scope import apply_data_scope
|
|
query = db.query(model).filter(model.id == record_id, model.tenant_no == tenant_no,
|
|
model.del_flag == 0)
|
|
query = apply_data_scope(query, model, user, db, tenant_no)
|
|
if lock:
|
|
query = query.populate_existing().with_for_update()
|
|
row = query.first()
|
|
if row is None:
|
|
raise HTTPException(404, '单据不存在或无权访问')
|
|
return row
|