| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854 |
- """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))
|