From ffbb5e36b3c40534a3fcde0995a393f26130f891 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Sat, 1 Aug 2026 13:03:35 +0800 Subject: [PATCH] feat(crm): implement quote approver setting model and upsert CRUD Co-authored-by: Cursor --- .../app/crud/crm/quote_approver_setting.py | 93 +++++++++++++++++++ backend/app/models/crm_models.py | 19 ++++ .../app/schemas/crm/quote_approver_setting.py | 10 ++ 3 files changed, 122 insertions(+) create mode 100644 backend/app/schemas/crm/quote_approver_setting.py diff --git a/backend/app/crud/crm/quote_approver_setting.py b/backend/app/crud/crm/quote_approver_setting.py index d6053d898..664fac021 100644 --- a/backend/app/crud/crm/quote_approver_setting.py +++ b/backend/app/crud/crm/quote_approver_setting.py @@ -32,3 +32,96 @@ def prefill_approver_ids( if valid_ids is not None: ids = [i for i in ids if str(i) in valid_ids] return [str(i) for i in ids if str(i).strip()] + + +from datetime import datetime + +from sqlalchemy.orm import Session + +from app.core.utils import generate_uuid +from app.models.crm_models import CrmQuoteApproverSetting +from app.models.models import SysUser + + +def _row_to_dict(row: CrmQuoteApproverSetting) -> Dict[str, Any]: + return { + "id": row.id, + "approverIds": parse_approver_ids(row.approver_ids), + "status": row.status or "0", + "tenantNo": row.tenant_no, + "updateTime": row.update_time.isoformat(sep=" ") if row.update_time else None, + } + + +def get_setting(db: Session, *, tenant_no: str) -> Optional[Dict[str, Any]]: + row = ( + db.query(CrmQuoteApproverSetting) + .filter( + CrmQuoteApproverSetting.tenant_no == tenant_no, + CrmQuoteApproverSetting.del_flag == 0, + ) + .order_by(CrmQuoteApproverSetting.update_time.desc()) + .first() + ) + return _row_to_dict(row) if row else None + + +def _assert_users_exist(db: Session, *, tenant_no: str, approver_ids: List[str]) -> None: + ids = [str(i).strip() for i in approver_ids if str(i).strip()] + if not ids: + return + rows = ( + db.query(SysUser.id) + .filter(SysUser.id.in_(ids), SysUser.del_flag == 0) + .all() + ) + found = {str(r[0]) for r in rows} + missing = [i for i in ids if i not in found] + if missing: + raise ValueError(f"审批人无效或不存在:{','.join(missing)}") + + +def save_setting( + db: Session, + *, + tenant_no: str, + approver_ids: List[str], + status: str, + user_id: str = None, + dept_id: str = "", +) -> Dict[str, Any]: + status_norm = "1" if str(status) == "1" else "0" + ids = [str(i).strip() for i in (approver_ids or []) if str(i).strip()] + _assert_users_exist(db, tenant_no=tenant_no, approver_ids=ids) + + row = ( + db.query(CrmQuoteApproverSetting) + .filter( + CrmQuoteApproverSetting.tenant_no == tenant_no, + CrmQuoteApproverSetting.del_flag == 0, + ) + .first() + ) + now = datetime.now() + if row: + row.approver_ids = join_approver_ids(ids) + row.status = status_norm + row.update_by = user_id + row.update_time = now + else: + row = CrmQuoteApproverSetting( + id=generate_uuid(), + approver_ids=join_approver_ids(ids), + status=status_norm, + tenant_no=tenant_no, + create_by=user_id, + create_dept_id=dept_id or "", + create_time=now, + update_by=user_id, + update_time=now, + del_flag=0, + ) + db.add(row) + db.commit() + db.refresh(row) + return _row_to_dict(row) diff --git a/backend/app/models/crm_models.py b/backend/app/models/crm_models.py index 92ad5e537..6410f5683 100644 --- a/backend/app/models/crm_models.py +++ b/backend/app/models/crm_models.py @@ -848,6 +848,25 @@ class CrmQuoteProduct(Base): del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记") +class CrmQuoteApproverSetting(Base): + """CRM-报价单审批人设置(租户级)""" + + __tablename__ = "crm_quote_approver_setting" + + id = Column(String(64), primary_key=True, comment="主键ID(UUID)") + approver_ids = Column(String(1000), nullable=False, default="", comment="有序审批人用户ID,逗号分隔") + status = Column(String(1), nullable=False, default="0", comment="0启用 1停用") + tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号") + order_num = Column(Integer, nullable=True, comment="排序号") + remark = Column(String(500), nullable=True, comment="备注") + create_by = Column(String(64), nullable=True, comment="创建者") + create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门") + create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间") + update_by = Column(String(64), nullable=True, comment="更新者") + update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间") + del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记") + + class CrmQuoteApproval(Base): """CRM-报价单审批记录表""" diff --git a/backend/app/schemas/crm/quote_approver_setting.py b/backend/app/schemas/crm/quote_approver_setting.py new file mode 100644 index 000000000..0b1d0c63b --- /dev/null +++ b/backend/app/schemas/crm/quote_approver_setting.py @@ -0,0 +1,10 @@ +from typing import List + +from pydantic import BaseModel, ConfigDict, Field + + +class QuoteApproverSettingSaveBody(BaseModel): + model_config = ConfigDict(populate_by_name=True) + + approverIds: List[str] = Field(default_factory=list) + status: str = Field(default="0") # 0启用 1停用