Files
shanxia2.0/backend/app/api/crm_contract_routes.py
T
2026-09-09 13:03:02 +08:00

855 lines
32 KiB
Python

"""CRM 合同 API 路由 — GET/PUT/DELETE/POST 对齐原 Java 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, require_menu_code
from app.core.oper_log_decorator import oper_log
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 (
batch_assign_owner,
batch_submit_contract_approval,
create_contract,
create_from_opportunity,
create_from_quote,
download_contract_pdf,
export_contracts,
finish_contract,
get_contract_detail,
get_template,
invalid_contract,
list_contracts,
query_expiring,
renew_contract,
save_template,
sign_contract,
soft_delete_contracts,
start_execute,
statistics_by_status,
statistics_by_type,
statistics_overview,
statistics_trend,
submit_contract_approval,
total_pages,
update_contract,
upload_attachments,
upload_attachments_with_category,
upload_file,
withdraw_contract_approval,
)
from app.crud.crm.contract_approval import (
approve_contract_by_contract_id,
list_contract_approvals,
)
from app.crud.crm.contract_approver_setting import get_setting as get_contract_approver_setting
from app.crud.crm.contract_approver_setting import save_setting as save_contract_approver_setting
from app.schemas.crm.contract_approver_setting import ContractApproverSettingSaveBody
from app.schemas.crm.contract import (
ContractApprovalActionBody,
ContractBatchAssignBody,
ContractBatchSubmitBody,
ContractCreateBody,
ContractExportBody,
ContractInvalidBody,
ContractListQuery,
ContractRenewBody,
ContractSignBody,
ContractStatisticsOverviewQuery,
ContractStatisticsTrendQuery,
ContractStatusBody,
ContractSubmitBody,
ContractTemplateSaveBody,
ContractUpdateBody,
ContractUploadAttachmentsBody,
ContractUploadFileBody,
ContractWithdrawBody,
)
from app.utils.crm_export_columns import CONTRACT_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_routes(router):
@router.get("/contract/list")
async def contract_list(
request: Request,
pageNum: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=500),
keyword: Optional[str] = Query(
None,
description="即时检索:合同编号/合同名称/客户名称/合同产品名称/产品拼音首字母",
),
contractNo: Optional[str] = None,
contractName: Optional[str] = None,
customerName: Optional[str] = None,
customerId: Optional[str] = None,
opportunityId: Optional[str] = None,
quoteId: Optional[str] = None,
contractType: Optional[str] = None,
status: Optional[str] = None,
excludeStatus: Optional[str] = None,
approvalStatus: Optional[str] = None,
ownerUserId: Optional[str] = None,
pendingApprovalUserId: Optional[str] = None,
approvedByUserId: Optional[str] = None,
minAmount: Optional[float] = None,
maxAmount: Optional[float] = None,
signDateBegin: Optional[str] = None,
signDateEnd: Optional[str] = None,
beginTime: Optional[str] = None,
endTime: Optional[str] = None,
includeProducts: bool = Query(False, description="是否附带合同产品明细"),
_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", "")
query = ContractListQuery(
pageNum=pageNum,
pageSize=pageSize,
keyword=keyword,
contractNo=contractNo,
contractName=contractName,
customerName=customerName,
customerId=customerId,
opportunityId=opportunityId,
quoteId=quoteId,
contractType=contractType,
status=status,
excludeStatus=excludeStatus,
approvalStatus=approvalStatus,
ownerUserId=ownerUserId,
pendingApprovalUserId=pendingApprovalUserId,
approvedByUserId=approvedByUserId,
minAmount=minAmount,
maxAmount=maxAmount,
signDateBegin=signDateBegin,
signDateEnd=signDateEnd,
beginTime=beginTime,
endTime=endTime,
)
filters = query.model_dump(
by_alias=True,
exclude={"pageNum", "pageSize"},
exclude_none=True,
)
# 列头漏斗等未在签名中声明的 query 参数一并透传
skip_keys = {
"pageNum",
"pageSize",
"includeProducts",
*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_contracts(
db,
tenant_no,
user_info=user_info,
page=query.pageNum,
page_size=query.pageSize,
filters=filters,
current_user_id=user_id,
include_products=includeProducts,
)
tp = total_pages(total, query.pageSize)
return success_response(
{
"list": rows,
"rows": rows,
"total": total,
"pageNum": query.pageNum,
"pageSize": query.pageSize,
"totalPages": tp,
}
)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract")
@oper_log(title="CRM合同管理", business_type=1, summary="新增合同【{contractName}】")
async def contract_add(
body: ContractCreateBody,
_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(
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")
@oper_log(title="CRM合同管理", business_type=2, summary="修改合同【{contractName}】")
async def contract_edit(
body: ContractUpdateBody,
_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 ""
data = body.model_dump(by_alias=True)
contract_id = data.pop("id")
detail = update_contract(
db,
contract_id,
tenant_no=tenant_no,
data=data,
user_id=user_id,
dept_id=dept_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/{ids}")
@oper_log(title="CRM合同管理", business_type=3, path_param="ids", summary="删除合同")
async def contract_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_contracts(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/submitApproval")
async def contract_submit_approval(
body: ContractSubmitBody,
_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 ""
submit_contract_approval(
db,
body.id,
tenant_no=tenant_no,
approver_ids=body.approverIds,
remark=body.remark,
user_id=user_id,
dept_id=dept_id,
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/batchSubmitApproval")
async def contract_batch_submit_approval(
body: ContractBatchSubmitBody,
_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 ""
count = batch_submit_contract_approval(
db,
body.ids,
tenant_no=tenant_no,
approver_ids=body.approverIds,
remark=body.remark,
user_id=user_id,
dept_id=dept_id,
user_info=user_info,
)
return success_response(count, message="批量提交完成")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.put("/contract/withdrawApproval")
async def contract_withdraw_approval(
body: ContractWithdrawBody,
_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_contract_approval(
db,
body.id,
tenant_no=tenant_no,
remark=body.remark,
user_id=user_id,
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/startExecute")
async def contract_start_execute(
body: ContractStatusBody,
_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", "")
start_execute(db, body.id, tenant_no=tenant_no, remark=body.remark, 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/finish")
async def contract_finish(
body: ContractStatusBody,
_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", "")
finish_contract(db, body.id, tenant_no=tenant_no, remark=body.remark, 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/invalid")
@oper_log(title="CRM合同管理", business_type=2, summary="作废合同")
async def contract_invalid(
body: ContractInvalidBody,
_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", "")
invalid_contract(
db,
body.id,
tenant_no=tenant_no,
invalid_reason=body.invalidReason,
remark=body.remark,
user_id=user_id,
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/saveTemplate")
async def contract_save_template(
body: ContractTemplateSaveBody,
_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)
save_template(
db,
body.id,
body.templateContent,
tenant_no=tenant_no,
settlement_clause_drafts=body.settlementClauseDrafts,
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.get("/contract/getTemplate/{contract_id}")
async def contract_get_template(
contract_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)
content = get_template(db, contract_id, tenant_no=tenant_no, user_info=user_info)
return success_response(content or "", message="获取模板成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/uploadFile")
async def contract_upload_file(
body: ContractUploadFileBody,
_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)
upload_file(db, body.id, body.fileUrl, tenant_no=tenant_no)
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/uploadAttachments")
async def contract_upload_attachments(
body: ContractUploadAttachmentsBody,
_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)
# attachments 显式传入(含 [])表示整表覆盖保存,允许清空扫描件
if body.attachments is not None:
upload_attachments_with_category(
db, body.id, body.attachments, tenant_no=tenant_no,
user_info=user_info,
)
elif body.ossIds:
upload_attachments(db, body.id, body.ossIds, tenant_no=tenant_no)
else:
return error_response(400, "附件参数不能为空")
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/export")
@oper_log(title="CRM合同管理", business_type=5, summary="导出合同列表")
async def contract_export(
body: ContractExportBody = 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 ContractExportBody()
filters = list_body.model_dump(
by_alias=True,
exclude={"pageNum", "pageSize"},
exclude_none=True,
)
rows = export_contracts(db, tenant_no, filters=filters)
rows = _filter_export_rows_by_ids(rows, getattr(list_body, "ids", None))
export_cols = filter_export_columns(CONTRACT_EXPORT_COLUMNS, getattr(list_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 ExportValidationError as e:
return error_response(400, str(e))
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/statistics/overview")
async def contract_statistics_overview(
ownerUserId: 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)
req = ContractStatisticsOverviewQuery(
ownerUserId=ownerUserId,
beginTime=beginTime,
endTime=endTime,
)
data = statistics_overview(
db,
tenant_no,
owner_user_id=req.ownerUserId,
begin_time=req.beginTime,
end_time=req.endTime,
user_info=user_info,
)
return success_response(data)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/statistics/status")
async def contract_statistics_status(
_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)
return success_response(statistics_by_status(db, tenant_no))
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/statistics/type")
async def contract_statistics_type(
_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)
return success_response(statistics_by_type(db, tenant_no))
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/statistics/trend")
async def contract_statistics_trend(
type: str = Query("month"),
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)
req = ContractStatisticsTrendQuery(type=type, beginTime=beginTime, endTime=endTime)
data = statistics_trend(
db,
tenant_no,
period_type=req.type or "month",
begin_time=req.beginTime,
end_time=req.endTime,
user_info=user_info,
)
return success_response(data)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/statistics/expiring")
async def contract_statistics_expiring(
days: int = Query(30, ge=1),
_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)
rows = query_expiring(db, tenant_no, days=days)
return success_response(rows)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/renew/{parent_id}")
async def contract_renew(
parent_id: str,
body: ContractRenewBody,
_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 ""
new_id = renew_contract(
db,
parent_id,
tenant_no=tenant_no,
data=body.model_dump(by_alias=True),
user_id=user_id,
dept_id=dept_id,
)
return success_response(new_id, message="续签成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/createFromQuote/{quote_id}")
async def contract_create_from_quote(
quote_id: str,
body: ContractCreateBody,
_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 ""
contract_id = create_from_quote(
db,
quote_id,
tenant_no=tenant_no,
data=body.model_dump(by_alias=True),
user_id=user_id,
dept_id=dept_id,
)
return success_response(contract_id, message="创建成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/createFromOpportunity/{opportunity_id}")
async def contract_create_from_opportunity(
opportunity_id: str,
body: ContractCreateBody,
_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 ""
contract_id = create_from_opportunity(
db,
opportunity_id,
tenant_no=tenant_no,
data=body.model_dump(by_alias=True),
user_id=user_id,
dept_id=dept_id,
)
return success_response(contract_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/sign")
async def contract_sign(
body: ContractSignBody,
_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", "")
sign_contract(
db,
body.id,
tenant_no=tenant_no,
actual_sign_date=body.actualSignDate,
contract_file=body.contractFile,
remark=body.remark or "",
user_id=user_id,
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/batch/assign")
async def contract_batch_assign(
body: ContractBatchAssignBody,
_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", "")
count = batch_assign_owner(
db,
body.ids,
tenant_no=tenant_no,
owner_user_id=body.ownerUserId,
remark=body.remark or "",
user_id=user_id,
user_info=user_info,
)
return success_response(count, message="分配成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/download/{contract_id}")
async def contract_download(
contract_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)
file_path = download_contract_pdf(db, contract_id, tenant_no=tenant_no)
return success_response(file_path)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract/approval")
async def contract_approval_by_contract_id(
body: ContractApprovalActionBody,
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_id = _user.get("user_id", "") or _user.get("id", "")
approve_contract_by_contract_id(
db,
body.id,
approval_result=body.approvalResult,
approval_opinion=body.approvalOpinion or "",
attachments=body.attachments or "",
remark=body.remark 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.get("/contract/approval/flow/{contract_id}")
async def contract_approval_flow(
contract_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)
rows = list_contract_approvals(db, contract_id, tenant_no=tenant_no)
return success_response(rows)
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.post("/contract-approver-setting/get")
async def contract_approver_setting_get(
_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
data = get_contract_approver_setting(db, tenant_no=tenant_no)
return success_response(data or {"approverIds": [], "status": "0"})
except Exception as e:
return error_response(500, str(e))
@router.post("/contract-approver-setting/save")
async def contract_approver_setting_save(
body: ContractApproverSettingSaveBody,
_user: dict = Depends(require_menu_code("system:approverSetting")),
db: Session = Depends(get_db),
):
try:
tenant_no = get_tenant_no(db, _user)
user_id = _user.get("user_id", "") or _user.get("id", "")
dept_id = _user.get("dept_id", "") or _user.get("create_dept_id", "") or ""
data = save_contract_approver_setting(
db,
tenant_no=tenant_no,
approver_ids=body.approverIds or [],
status=body.status or "0",
user_id=user_id,
dept_id=dept_id,
)
return success_response(data, message="保存成功")
except ValueError as e:
return error_response(400, str(e))
except Exception as e:
return error_response(500, str(e))
@router.get("/contract/{contract_id}")
async def contract_detail(
contract_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", "")
detail = get_contract_detail(
db,
contract_id,
tenant_no=tenant_no,
current_user_id=user_id,
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))