Files
shanxia2.0/backend/app/api/crm_contract_sub_routes.py
wuzilongandCursor 6a8cd90b98 feat: cascade column facet options by current list context
Make dynamic column-facet values respect other active filters (Excel-style), with backend facet context helpers, list-page wiring, slip print/sidebar fixes, and refreshed graphify graphs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-11 22:04:20 +08:00

840 lines
32 KiB
Python

"""CRM 合同子模块路由 — 变更/模板/审批独立页"""
from __future__ import annotations
from datetime import datetime
from typing import Optional
from fastapi import Depends, Query, Request
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.menu_guard import require_admin_or_super_admin
from app.core.response import error_response, success_response
from app.core.tenant_context import get_tenant_no
from app.crud.crm.data_scope_helpers import crm_user_info
from app.crud.crm.contract import (
create_contract_change,
create_contract_template,
export_contract_changes,
export_contract_templates,
execute_change,
get_contract_change_detail,
get_contract_template_detail,
list_contract_change_column_facet_values,
list_contract_changes,
list_contract_template_column_facet_values,
list_contract_templates,
soft_delete_contract_changes,
soft_delete_contract_templates,
submit_change_approval,
toggle_contract_template_active,
total_pages,
update_contract_change,
update_contract_template,
withdraw_change,
)
from app.crud.crm.contract_approval import (
approve_pass,
approve_reject,
approve_transfer,
export_contract_approvals,
get_contract_approval_detail,
list_contract_approval_column_facet_values,
list_contract_approvals_page,
refresh_approver_names,
)
from app.schemas.crm.contract import (
ContractApprovalColumnFacetBody,
ContractApprovalExportBody,
ContractApprovalListQuery,
ContractApprovalPassBody,
ContractApprovalRefreshNamesBody,
ContractApprovalRejectBody,
ContractApprovalTransferBody,
ContractChangeColumnFacetBody,
ContractChangeCreateBody,
ContractChangeExportBody,
ContractChangeListQuery,
ContractChangeSubmitBody,
ContractChangeUpdateBody,
ContractTemplateColumnFacetBody,
ContractTemplateCreateBody,
ContractTemplateExportBody,
ContractTemplateListQuery,
ContractTemplateUpdateBody,
)
from app.utils.crm_export_columns import (
CONTRACT_APPROVAL_EXPORT_COLUMNS,
CONTRACT_CHANGE_EXPORT_COLUMNS,
CONTRACT_TEMPLATE_EXPORT_COLUMNS,
)
from app.utils.excel_export import (
ExportValidationError,
export_rows_to_xlsx_response,
filter_export_columns,
)
from app.api.crm import _filter_export_rows_by_ids
def register_contract_sub_routes(router):
# --- 合同变更 ---
@router.get("/contract/change/list")
async def contract_change_list(
request: Request,
pageNum: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=500),
contractId: Optional[str] = None,
contractNo: Optional[str] = None,
contractName: Optional[str] = None,
changeType: Optional[str] = None,
approvalStatus: Optional[str] = None,
beginTime: Optional[str] = None,
endTime: Optional[str] = None,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
query = ContractChangeListQuery(
pageNum=pageNum,
pageSize=pageSize,
contractId=contractId,
contractNo=contractNo,
contractName=contractName,
changeType=changeType,
approvalStatus=approvalStatus,
beginTime=beginTime,
endTime=endTime,
)
filters = query.model_dump(
by_alias=True,
exclude={"pageNum", "pageSize"},
exclude_none=True,
)
if query.model_extra:
filters.update(
{
k: v
for k, v in query.model_extra.items()
if v is not None and str(v).strip() != ""
}
)
# 列头漏斗等未在签名中声明的 query 参数一并透传
skip_keys = {"pageNum", "pageSize", *filters.keys()}
for key, val in request.query_params.multi_items():
if key in skip_keys or val is None or str(val).strip() == "":
continue
filters[key] = val
rows, total = list_contract_changes(
db,
tenant_no,
user_info=user_info,
page=query.pageNum,
page_size=query.pageSize,
filters=filters,
)
return success_response(
{
"list": rows,
"rows": rows,
"total": total,
"pageNum": query.pageNum,
"pageSize": query.pageSize,
"totalPages": total_pages(total, query.pageSize),
}
)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/change/column-facet-values")
async def contract_change_column_facet_values(
body: ContractChangeColumnFacetBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
"""合同变更列表列头可选值(合同编号/名称去重;Excel 级联上下文)"""
try:
from app.services.crm.facet_context import facet_filter_kwargs_from_body
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
filter_kwargs = facet_filter_kwargs_from_body(body, body.field)
rows = list_contract_change_column_facet_values(
db,
tenant_no,
field=body.field,
keyword=body.keyword,
limit=body.limit if body.limit is not None else 500,
user_info=user_info,
filter_kwargs=filter_kwargs,
)
return success_response({"list": rows})
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/change/{change_id}")
async def contract_change_detail(
change_id: str,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
detail = get_contract_change_detail(db, change_id, tenant_no=tenant_no, user_info=user_info)
return success_response(detail)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/change")
async def contract_change_add(
body: ContractChangeCreateBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
dept_id = _user.get("dept_id", "") or _user.get("create_dept_id", "") or ""
detail = create_contract_change(
db,
tenant_no=tenant_no,
data=body.model_dump(by_alias=True),
user_id=user_id,
dept_id=dept_id,
)
return success_response(detail["id"], message="新增成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.put("/contract/change")
async def contract_change_edit(
body: ContractChangeUpdateBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
data = body.model_dump(by_alias=True)
change_id = data.pop("id")
detail = update_contract_change(
db,
change_id,
tenant_no=tenant_no,
data=data,
user_id=user_id,
user_info=user_info,
)
return success_response(detail, message="修改成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.delete("/contract/change/{ids}")
async def contract_change_remove(
ids: str,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
id_list = [x.strip() for x in ids.split(",") if x.strip()]
soft_delete_contract_changes(db, id_list, tenant_no=tenant_no, user_info=user_info)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/change/submitApproval")
async def contract_change_submit_approval(
body: ContractChangeSubmitBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
submit_change_approval(
db,
body.id,
tenant_no=tenant_no,
approver_ids=body.approverIds,
remark=body.remark or "",
user_id=user_id,
)
return success_response(None, message="提交成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.put("/contract/change/withdraw/{change_id}")
async def contract_change_withdraw(
change_id: str,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
withdraw_change(db, change_id, tenant_no=tenant_no, user_id=user_id)
return success_response(None, message="撤回成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.put("/contract/change/execute/{change_id}")
async def contract_change_execute(
change_id: str,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
execute_change(db, change_id, tenant_no=tenant_no, user_id=user_id)
return success_response(None, message="执行成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/change/export")
async def contract_change_export(
body: ContractChangeExportBody = None,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
list_body = body or ContractChangeExportBody()
filters = list_body.model_dump(
by_alias=True,
exclude={"pageNum", "pageSize"},
exclude_none=True,
)
if list_body.model_extra:
filters.update(
{
k: v
for k, v in list_body.model_extra.items()
if v is not None and str(v).strip() != ""
}
)
rows = export_contract_changes(db, tenant_no, filters=filters)
rows = _filter_export_rows_by_ids(rows, getattr(list_body, "ids", None) or getattr(body, "ids", None))
export_cols = filter_export_columns(CONTRACT_CHANGE_EXPORT_COLUMNS, getattr(list_body, "columns", None) or getattr(body, "columns", None))
return export_rows_to_xlsx_response(
db,
tenant_no=tenant_no,
sheet_title="合同变更记录",
columns=export_cols,
rows=rows,
filename_stem=f"合同变更_{datetime.now().strftime('%Y%m%d%H%M%S')}",
include_legacy_filename=False,
)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
# --- 合同模板库 ---
@router.get("/contract/template/list")
async def contract_template_list(
request: Request,
pageNum: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=500),
templateNo: Optional[str] = None,
templateName: Optional[str] = None,
templateType: Optional[str] = None,
isActive: Optional[int] = None,
beginTime: Optional[str] = None,
endTime: Optional[str] = None,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
query = ContractTemplateListQuery(
pageNum=pageNum,
pageSize=pageSize,
templateNo=templateNo,
templateName=templateName,
templateType=templateType,
isActive=isActive,
beginTime=beginTime,
endTime=endTime,
)
filters = query.model_dump(
by_alias=True,
exclude={"pageNum", "pageSize"},
exclude_none=True,
)
if query.model_extra:
filters.update(
{
k: v
for k, v in query.model_extra.items()
if v is not None and str(v).strip() != ""
}
)
skip_keys = {"pageNum", "pageSize", *filters.keys()}
for key, val in request.query_params.multi_items():
if key in skip_keys or val is None or str(val).strip() == "":
continue
filters[key] = val
rows, total = list_contract_templates(
db,
tenant_no,
user_info=user_info,
page=query.pageNum,
page_size=query.pageSize,
filters=filters,
)
return success_response(
{
"list": rows,
"rows": rows,
"total": total,
"pageNum": query.pageNum,
"pageSize": query.pageSize,
"totalPages": total_pages(total, query.pageSize),
}
)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/template/column-facet-values")
async def contract_template_column_facet_values(
body: ContractTemplateColumnFacetBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
"""合同模板列表列头可选值(编号/名称去重;Excel 级联上下文)"""
try:
from app.services.crm.facet_context import facet_filter_kwargs_from_body
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
filter_kwargs = facet_filter_kwargs_from_body(body, body.field)
rows = list_contract_template_column_facet_values(
db,
tenant_no,
field=body.field,
keyword=body.keyword,
limit=body.limit if body.limit is not None else 500,
user_info=user_info,
filter_kwargs=filter_kwargs,
)
return success_response({"list": rows})
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/template/{template_id}")
async def contract_template_detail(
template_id: str,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
detail = get_contract_template_detail(db, template_id, tenant_no=tenant_no)
return success_response(detail)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/template")
async def contract_template_add(
body: ContractTemplateCreateBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
dept_id = _user.get("dept_id", "") or _user.get("create_dept_id", "") or ""
detail = create_contract_template(
db,
tenant_no=tenant_no,
data=body.model_dump(by_alias=True),
user_id=user_id,
dept_id=dept_id,
)
return success_response(detail["id"], message="新增成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.put("/contract/template")
async def contract_template_edit(
body: ContractTemplateUpdateBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
data = body.model_dump(by_alias=True)
template_id = data.pop("id")
detail = update_contract_template(
db,
template_id,
tenant_no=tenant_no,
data=data,
user_id=user_id,
user_info=user_info,
)
return success_response(detail, message="修改成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.delete("/contract/template/{ids}")
async def contract_template_remove(
ids: str,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
id_list = [x.strip() for x in ids.split(",") if x.strip()]
soft_delete_contract_templates(db, id_list, tenant_no=tenant_no, user_info=user_info)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.put("/contract/template/enable/{template_id}")
async def contract_template_enable(
template_id: str,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
toggle_contract_template_active(
db, template_id, tenant_no=tenant_no, is_active=1, user_id=user_id
)
return success_response(None, message="启用成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.put("/contract/template/disable/{template_id}")
async def contract_template_disable(
template_id: str,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
toggle_contract_template_active(
db, template_id, tenant_no=tenant_no, is_active=0, user_id=user_id
)
return success_response(None, message="停用成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/template/export")
async def contract_template_export(
body: ContractTemplateExportBody = None,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
list_body = body or ContractTemplateExportBody()
filters = list_body.model_dump(
by_alias=True,
exclude={"pageNum", "pageSize"},
exclude_none=True,
)
if list_body.model_extra:
filters.update(
{
k: v
for k, v in list_body.model_extra.items()
if v is not None and str(v).strip() != ""
}
)
rows = export_contract_templates(db, tenant_no, filters=filters)
rows = _filter_export_rows_by_ids(rows, getattr(list_body, "ids", None) or getattr(body, "ids", None))
export_cols = filter_export_columns(CONTRACT_TEMPLATE_EXPORT_COLUMNS, getattr(list_body, "columns", None) or getattr(body, "columns", None))
return export_rows_to_xlsx_response(
db,
tenant_no=tenant_no,
sheet_title="合同模板",
columns=export_cols,
rows=rows,
filename_stem=f"合同模板_{datetime.now().strftime('%Y%m%d%H%M%S')}",
include_legacy_filename=False,
)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
# --- 审批记录独立页 ---
@router.get("/contract/approval/list")
async def contract_approval_list(
request: Request,
pageNum: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=500),
contractId: Optional[str] = None,
contractNo: Optional[str] = None,
contractName: Optional[str] = None,
approverName: Optional[str] = None,
approvalResult: Optional[str] = None,
beginTime: Optional[str] = None,
endTime: Optional[str] = None,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
query = ContractApprovalListQuery(
pageNum=pageNum,
pageSize=pageSize,
contractId=contractId,
contractNo=contractNo,
contractName=contractName,
approverName=approverName,
approvalResult=approvalResult,
beginTime=beginTime,
endTime=endTime,
)
filters = query.model_dump(
by_alias=True,
exclude={"pageNum", "pageSize"},
exclude_none=True,
)
if query.model_extra:
filters.update(
{
k: v
for k, v in query.model_extra.items()
if v is not None and str(v).strip() != ""
}
)
skip_keys = {"pageNum", "pageSize", *filters.keys()}
for key, val in request.query_params.multi_items():
if key in skip_keys or val is None or str(val).strip() == "":
continue
filters[key] = val
rows, total = list_contract_approvals_page(
db,
tenant_no,
page=query.pageNum,
page_size=query.pageSize,
filters=filters,
)
return success_response(
{
"list": rows,
"rows": rows,
"total": total,
"pageNum": query.pageNum,
"pageSize": query.pageSize,
"totalPages": total_pages(total, query.pageSize),
}
)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/approval/column-facet-values")
async def contract_approval_column_facet_values(
body: ContractApprovalColumnFacetBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
"""合同审批记录列头可选值(合同编号/名称去重;Excel 级联上下文)"""
try:
from app.services.crm.facet_context import facet_filter_kwargs_from_body
tenant_no = get_tenant_no(db, _user)
filter_kwargs = facet_filter_kwargs_from_body(body, body.field)
rows = list_contract_approval_column_facet_values(
db,
tenant_no,
field=body.field,
keyword=body.keyword,
limit=body.limit if body.limit is not None else 500,
filter_kwargs=filter_kwargs,
)
return success_response({"list": rows})
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/approval/{approval_id}")
async def contract_approval_detail(
approval_id: str,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
detail = get_contract_approval_detail(db, approval_id, tenant_no=tenant_no)
return success_response(detail)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/approval/pass")
async def contract_approval_pass(
body: ContractApprovalPassBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
user_id = _user.get("user_id", "") or _user.get("id", "")
approve_pass(db, body.id, approval_opinion=body.approvalOpinion or "", user_id=user_id)
db.commit()
return success_response(None, message="审批通过")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/approval/reject")
async def contract_approval_reject(
body: ContractApprovalRejectBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
user_id = _user.get("user_id", "") or _user.get("id", "")
approve_reject(db, body.id, approval_opinion=body.approvalOpinion, user_id=user_id)
db.commit()
return success_response(None, message="已驳回")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/approval/transfer")
async def contract_approval_transfer(
body: ContractApprovalTransferBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
user_id = _user.get("user_id", "") or _user.get("id", "")
approve_transfer(
db,
body.id,
target_approver_id=body.targetApproverId,
transfer_reason=body.transferReason,
user_id=user_id,
)
db.commit()
return success_response(None, message="转审成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/approval/export")
async def contract_approval_export(
body: ContractApprovalExportBody = None,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
list_body = body or ContractApprovalExportBody()
filters = list_body.model_dump(
by_alias=True,
exclude={"pageNum", "pageSize"},
exclude_none=True,
)
if list_body.model_extra:
filters.update(
{
k: v
for k, v in list_body.model_extra.items()
if v is not None and str(v).strip() != ""
}
)
rows = export_contract_approvals(db, tenant_no, filters=filters)
rows = _filter_export_rows_by_ids(rows, getattr(list_body, "ids", None) or getattr(body, "ids", None))
export_cols = filter_export_columns(CONTRACT_APPROVAL_EXPORT_COLUMNS, getattr(list_body, "columns", None) or getattr(body, "columns", None))
return export_rows_to_xlsx_response(
db,
tenant_no=tenant_no,
sheet_title="合同审批记录",
columns=export_cols,
rows=rows,
filename_stem=f"合同审批_{datetime.now().strftime('%Y%m%d%H%M%S')}",
include_legacy_filename=False,
)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/approval/refreshNames")
async def contract_approval_refresh_names(
body: ContractApprovalRefreshNamesBody = None,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
req = body or ContractApprovalRefreshNamesBody()
count = refresh_approver_names(db, contract_id=req.contractId)
db.commit()
return success_response(count)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))