feat(crm): 联系人、产品、报价与合同域接入数据权限过滤

补全 PR3 Phase 2.4–2.7,列表 apply_data_scope、详情/CUD assert_row_in_data_scope,合同/报价主表支持 owner_user_id。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-06-28 21:00:12 +08:00
1 parent ee531e9cfe
commit bf73b6b2d8
15 files changed
+598 -82

No files matched your search

+78 -16
View File
@@ -17,6 +17,8 @@ from app.core.tenant_context import get_tenant_no
from app.crud.crm.data_scope_helpers import (
crm_user_info,
ensure_crm_create_by_row_in_scope,
ensure_crm_contact_row_in_scope,
ensure_crm_customer_linked_row_in_scope,
ensure_crm_owner_row_in_scope,
)
from app.utils.crm_export_columns import (
@@ -329,6 +331,8 @@ async def category_tree(
"""获取产品分类树"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_info = crm_user_info(_user)
payload = body or {}
category_name = payload.get("categoryName") or payload.get("category_name")
status = payload.get("status")
@@ -337,6 +341,7 @@ async def category_tree(
tenant_no,
category_name=category_name,
status=status,
user_info=user_info,
)
return success_response(rows)
except ValueError as e:
@@ -516,6 +521,7 @@ async def category_add(
"""新增产品分类"""
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(exclude_unset=True)
obj = create_category(db, tenant_no=tenant_no, user_id=user_id, **data)
@@ -537,7 +543,7 @@ async def category_update(
user_id = _user.get("user_id", "") or _user.get("id", "")
data = body.model_dump(exclude_unset=True)
category_id = data.pop("id")
obj = update_category(db, category_id, user_id=user_id, **data)
obj = update_category(db, category_id, user_id=user_id, user_info=user_info, **data)
return success_response(_category_row_to_dict(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@@ -553,7 +559,7 @@ async def category_delete(
):
"""删除产品分类"""
try:
soft_delete_category(db, body.id)
soft_delete_category(db, body.id, user_info=user_info)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
@@ -573,6 +579,7 @@ async def product_list(
"""分页查询产品列表"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
rows, total = list_products(
db,
tenant_no,
@@ -581,6 +588,7 @@ async def product_list(
keyword=body.keyword,
category_id=body.category_id,
status=body.status,
user_info=user_info,
)
tp = total_pages(total, body.pageSize)
return success_response(
@@ -606,9 +614,12 @@ async def product_detail(
):
"""获取产品详情"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
obj = get_product(db, body.id)
if not obj:
return error_response(404, "产品不存在")
ensure_crm_create_by_row_in_scope(db, obj, user_info, tenant_no, message="无权访问该产品")
return success_response(_product_row_to_dict(obj))
except ValueError as e:
return error_response(400, str(e))
@@ -625,6 +636,7 @@ async def product_add(
"""新增产品"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
obj = create_product(
db,
@@ -650,7 +662,9 @@ async def product_update(
user_id = _user.get("user_id", "") or _user.get("id", "")
data = body.model_dump(exclude_unset=True)
product_id = data.pop("id")
obj = update_product(db, product_id, user_id=user_id, **data)
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
obj = update_product(db, product_id, user_id=user_id, user_info=user_info, **data)
return success_response(_product_row_to_dict(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@@ -666,6 +680,8 @@ async def product_delete(
):
"""删除产品(支持单条 body.id 和批量 body.ids)"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
ids_to_delete: List[str] = []
if body.ids:
ids_to_delete = body.ids
@@ -675,7 +691,7 @@ async def product_delete(
return error_response(400, "请传入 id 或 ids")
for pid in ids_to_delete:
soft_delete_product(db, pid)
soft_delete_product(db, pid, user_info=user_info)
return success_response(None, message="删除成功")
except ValueError as e:
@@ -692,10 +708,12 @@ async def product_update_status(
):
"""批量上架/下架"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
status_label = "上架" if body.status == "on" else "下架"
for pid in body.ids:
update_product(db, pid, user_id=user_id, status=body.status)
update_product(db, pid, user_id=user_id, user_info=user_info, status=body.status)
return success_response(None, message=f"批量{status_label}成功")
except ValueError as e:
return error_response(400, str(e))
@@ -712,11 +730,13 @@ async def product_options(
"""获取产品下拉选项"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
options = list_product_options(
db,
tenant_no,
keyword=body.keyword,
category_id=body.category_id,
user_info=user_info,
)
return success_response(options)
except ValueError as e:
@@ -739,6 +759,7 @@ async def product_import(
from openpyxl import load_workbook
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
content = await file.read()
@@ -833,6 +854,7 @@ async def product_export(
"""Excel 导出产品列表"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
rows, _ = list_products(
db,
tenant_no,
@@ -1424,10 +1446,11 @@ async def contact_list(
"""联系人分页列表"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
page = body.page if body else 1
page_size = body.pageSize if body else 10
rows, total = list_contacts(
db, tenant_no, page=page, page_size=page_size,
db, tenant_no, page=page, page_size=page_size, user_info=user_info,
keyword=body.keyword if body else None,
contact_name=body.contact_name if body else None,
mobile=body.mobile if body else None,
@@ -1461,9 +1484,12 @@ async def contact_detail(
contact_id = body.get("id")
if not contact_id:
return error_response(400, "缺少联系人ID")
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
row = get_contact(db, contact_id)
if not row:
return error_response(404, "联系人不存在")
ensure_crm_contact_row_in_scope(db, row, user_info, tenant_no, message="无权访问该联系人")
return success_response(contact_row_to_dict(row))
except ValueError as e:
return error_response(400, str(e))
@@ -1480,10 +1506,11 @@ async def contact_by_customer(
"""按客户ID查询联系人"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
customer_id = body.get("customerId", "")
if not customer_id:
return error_response(400, "缺少客户ID")
rows = list_contacts_by_customer(db, tenant_no, customer_id)
rows = list_contacts_by_customer(db, tenant_no, customer_id, user_info=user_info)
return success_response(rows)
except ValueError as e:
return error_response(400, str(e))
@@ -1500,9 +1527,11 @@ async def contact_add(
"""新增联系人"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
user_info = crm_user_info(_user)
obj = create_contact(
db, tenant_no=tenant_no, user_id=user_id,
db, tenant_no=tenant_no, user_id=user_id, user_info=user_info,
**body.model_dump(exclude_unset=True),
)
return success_response(contact_row_to_dict(obj), message="创建成功")
@@ -1523,7 +1552,9 @@ async def contact_update(
user_id = _user.get("user_id", "") or _user.get("id", "")
data = body.model_dump(exclude_unset=True)
contact_id = data.pop("id")
obj = update_contact(db, contact_id, user_id=user_id, **data)
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
obj = update_contact(db, contact_id, user_id=user_id, tenant_no=tenant_no, user_info=user_info, **data)
return success_response(contact_row_to_dict(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@@ -1539,8 +1570,11 @@ async def contact_delete(
):
"""删除联系人"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
for cid in body.ids:
soft_delete_contact(db, cid)
soft_delete_contact(db, cid, user_id=user_id, tenant_no=tenant_no, user_info=user_info)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
@@ -1560,7 +1594,9 @@ async def contact_set_primary(
if not contact_id:
return error_response(400, "缺少联系人ID")
user_id = _user.get("user_id", "") or _user.get("id", "")
obj = set_primary_contact(db, contact_id, user_id=user_id)
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
obj = set_primary_contact(db, contact_id, user_id=user_id, tenant_no=tenant_no, user_info=user_info)
return success_response(contact_row_to_dict(obj), message="设置成功")
except ValueError as e:
return error_response(400, str(e))
@@ -1577,8 +1613,9 @@ async def contact_export(
"""导出联系人列表"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
rows, _ = list_contacts(
db, tenant_no, page=1, page_size=10000,
db, tenant_no, page=1, page_size=10000, user_info=user_info,
keyword=body.keyword if body else None,
customer_id=body.customer_id if body else None,
)
@@ -1606,10 +1643,11 @@ async def contact_decision(
"""决策人联系人列表"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
page = body.page if body else 1
page_size = body.pageSize if body else 10
rows, total = list_contacts(
db, tenant_no, page=page, page_size=page_size,
db, tenant_no, page=page, page_size=page_size, user_info=user_info,
is_decision=True,
keyword=body.keyword if body else None,
)
@@ -1636,10 +1674,11 @@ async def contact_primary(
"""主联系人列表"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
page = body.page if body else 1
page_size = body.pageSize if body else 10
rows, total = list_contacts(
db, tenant_no, page=page, page_size=page_size,
db, tenant_no, page=page, page_size=page_size, user_info=user_info,
is_primary=True,
keyword=body.keyword if body else None,
)
@@ -1666,10 +1705,11 @@ async def contact_birthday(
"""本月生日联系人列表"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
page = body.page if body else 1
page_size = body.pageSize if body else 10
rows, total = list_contacts(
db, tenant_no, page=page, page_size=page_size,
db, tenant_no, page=page, page_size=page_size, user_info=user_info,
birthday_month=datetime.now().month,
keyword=body.keyword if body else None,
)
@@ -3044,10 +3084,12 @@ async def supplier_info_list(
"""分页查询供方列表 — Java: CrmSupplierInfoController.list"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
list_body = body or SupplierInfoListBody()
rows, total = list_supplier_info(
db,
tenant_no,
user_info=user_info,
page=list_body.page,
page_size=list_body.pageSize,
supplier_name=list_body.supplier_name,
@@ -3077,10 +3119,12 @@ async def supplier_info_list_all(
"""供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
list_body = body or SupplierInfoListAllBody()
rows = list_all_supplier_info(
db,
tenant_no,
user_info=user_info,
supplier_name=list_body.supplier_name,
status=list_body.status,
)
@@ -3100,9 +3144,13 @@ async def supplier_info_detail(
"""供方详情 — Java: CrmSupplierInfoController.getInfo"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
obj = get_supplier_info(db, body.id, tenant_no=tenant_no)
if not obj:
return error_response(404, "供方信息不存在")
ensure_crm_create_by_row_in_scope(
db, obj, user_info, tenant_no, message="无权访问该供方信息"
)
return success_response(supplier_info_row_to_dict(obj))
except ValueError as e:
return error_response(400, str(e))
@@ -3119,6 +3167,7 @@ async def supplier_info_add(
"""新增供方 — Java: CrmSupplierInfoController.add"""
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 ""
obj = create_supplier_info(
@@ -3144,6 +3193,7 @@ async def supplier_info_update(
"""修改供方 — Java: CrmSupplierInfoController.edit"""
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(exclude_unset=True)
supplier_id = data.pop("id")
@@ -3152,6 +3202,7 @@ async def supplier_info_update(
supplier_id,
tenant_no=tenant_no,
user_id=user_id,
user_info=user_info,
**data,
)
return success_response(supplier_info_row_to_dict(obj), message="修改成功")
@@ -3170,6 +3221,7 @@ async def supplier_info_delete(
"""删除供方 — Java: CrmSupplierInfoController.remove"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
ids_to_delete: List[str] = []
if body.ids:
@@ -3198,10 +3250,12 @@ async def supplier_info_export(
"""导出供方列表 — Java: CrmSupplierInfoController.export"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
list_body = body or SupplierInfoListBody()
rows, _ = list_supplier_info(
db,
tenant_no,
user_info=user_info,
page=1,
page_size=10000,
supplier_name=list_body.supplier_name,
@@ -3231,7 +3285,10 @@ async def _invoice_info_by_customer_impl(
db: Session,
):
tenant_no = get_tenant_no(db, _user)
rows = list_invoice_info_by_customer(db, tenant_no, body.customer_id)
user_info = crm_user_info(_user)
rows = list_invoice_info_by_customer(
db, tenant_no, body.customer_id, user_info=user_info
)
return success_response(rows)
@@ -3274,11 +3331,13 @@ async def invoice_info_add(
"""新增开票信息"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
obj = create_invoice_info(
db,
tenant_no=tenant_no,
user_id=user_id,
user_info=user_info,
**body.model_dump(exclude_unset=True),
)
return success_response(invoice_info_row_to_dict(obj), message="创建成功")
@@ -3297,6 +3356,7 @@ async def invoice_info_update(
"""更新开票信息"""
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(exclude_unset=True)
invoice_id = data.pop("id")
@@ -3305,6 +3365,7 @@ async def invoice_info_update(
invoice_id,
tenant_no=tenant_no,
user_id=user_id,
user_info=user_info,
**data,
)
return success_response(invoice_info_row_to_dict(obj), message="更新成功")
@@ -3346,6 +3407,7 @@ async def invoice_info_set_default(
"""设置默认开票信息"""
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
obj = set_default_invoice_info(
db,
+45 -1
View File
@@ -11,6 +11,7 @@ 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 (
batch_assign_owner,
batch_submit_contract_approval,
@@ -99,6 +100,7 @@ def register_contract_routes(router):
):
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,
@@ -131,6 +133,7 @@ def register_contract_routes(router):
rows, total = list_contracts(
db,
tenant_no,
user_info=user_info,
page=query.pageNum,
page_size=query.pageSize,
filters=filters,
@@ -160,6 +163,7 @@ def register_contract_routes(router):
):
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(
@@ -183,6 +187,7 @@ def register_contract_routes(router):
):
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)
@@ -194,6 +199,7 @@ def register_contract_routes(router):
data=data,
user_id=user_id,
dept_id=dept_id,
user_info=user_info,
)
return success_response(detail, message="修改成功")
except ValueError as e:
@@ -209,6 +215,7 @@ def register_contract_routes(router):
):
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)
return success_response(None, message="删除成功")
@@ -225,6 +232,7 @@ def register_contract_routes(router):
):
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(
@@ -235,6 +243,7 @@ def register_contract_routes(router):
remark=body.remark,
user_id=user_id,
dept_id=dept_id,
user_info=user_info,
)
return success_response(None, message="提交成功")
except ValueError as e:
@@ -250,6 +259,7 @@ def register_contract_routes(router):
):
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(
@@ -260,6 +270,7 @@ def register_contract_routes(router):
remark=body.remark,
user_id=user_id,
dept_id=dept_id,
user_info=user_info,
)
return success_response(count, message="批量提交完成")
except ValueError as e:
@@ -275,6 +286,7 @@ def register_contract_routes(router):
):
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,
@@ -282,6 +294,7 @@ def register_contract_routes(router):
tenant_no=tenant_no,
remark=body.remark,
user_id=user_id,
user_info=user_info,
)
return success_response(None, message="撤回成功")
except ValueError as e:
@@ -297,6 +310,7 @@ def register_contract_routes(router):
):
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="操作成功")
@@ -313,6 +327,7 @@ def register_contract_routes(router):
):
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="操作成功")
@@ -329,6 +344,7 @@ def register_contract_routes(router):
):
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,
@@ -337,6 +353,7 @@ def register_contract_routes(router):
invalid_reason=body.invalidReason,
remark=body.remark,
user_id=user_id,
user_info=user_info,
)
return success_response(None, message="作废成功")
except ValueError as e:
@@ -352,12 +369,14 @@ def register_contract_routes(router):
):
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:
@@ -373,6 +392,7 @@ def register_contract_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
content = get_template(db, contract_id, tenant_no=tenant_no)
return success_response(content or "", message="获取模板成功")
except ValueError as e:
@@ -388,6 +408,7 @@ def register_contract_routes(router):
):
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:
@@ -403,9 +424,11 @@ def register_contract_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
if body.attachments:
upload_attachments_with_category(
db, body.id, body.attachments, tenant_no=tenant_no
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)
@@ -425,6 +448,7 @@ def register_contract_routes(router):
):
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,
@@ -456,6 +480,7 @@ def register_contract_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
req = ContractStatisticsOverviewQuery(
ownerUserId=ownerUserId,
beginTime=beginTime,
@@ -467,6 +492,7 @@ def register_contract_routes(router):
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:
@@ -481,6 +507,7 @@ def register_contract_routes(router):
):
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))
@@ -494,6 +521,7 @@ def register_contract_routes(router):
):
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))
@@ -510,6 +538,7 @@ def register_contract_routes(router):
):
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,
@@ -517,6 +546,7 @@ def register_contract_routes(router):
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:
@@ -532,6 +562,7 @@ def register_contract_routes(router):
):
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:
@@ -548,6 +579,7 @@ def register_contract_routes(router):
):
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(
@@ -573,6 +605,7 @@ def register_contract_routes(router):
):
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(
@@ -598,6 +631,7 @@ def register_contract_routes(router):
):
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(
@@ -622,6 +656,7 @@ def register_contract_routes(router):
):
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,
@@ -631,6 +666,7 @@ def register_contract_routes(router):
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:
@@ -646,6 +682,7 @@ def register_contract_routes(router):
):
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,
@@ -654,6 +691,7 @@ def register_contract_routes(router):
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:
@@ -669,6 +707,7 @@ def register_contract_routes(router):
):
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:
@@ -684,6 +723,7 @@ def register_contract_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
approve_contract_by_contract_id(
db,
@@ -693,6 +733,7 @@ def register_contract_routes(router):
attachments=body.attachments or "",
remark=body.remark or "",
user_id=user_id,
user_info=user_info,
)
db.commit()
return success_response(None, message="审批成功")
@@ -709,6 +750,7 @@ def register_contract_routes(router):
):
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:
@@ -724,12 +766,14 @@ def register_contract_routes(router):
):
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:
+28 -3
View File
@@ -11,6 +11,7 @@ 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,
@@ -82,6 +83,7 @@ def register_contract_sub_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
query = ContractChangeListQuery(
pageNum=pageNum,
pageSize=pageSize,
@@ -96,6 +98,7 @@ def register_contract_sub_routes(router):
rows, total = list_contract_changes(
db,
tenant_no,
user_info=user_info,
page=query.pageNum,
page_size=query.pageSize,
filters=query.model_dump(by_alias=True, exclude={"pageNum", "pageSize"}, exclude_none=True),
@@ -123,7 +126,8 @@ def register_contract_sub_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
detail = get_contract_change_detail(db, change_id, tenant_no=tenant_no)
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))
@@ -138,6 +142,7 @@ def register_contract_sub_routes(router):
):
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(
@@ -161,6 +166,7 @@ def register_contract_sub_routes(router):
):
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")
@@ -170,6 +176,7 @@ def register_contract_sub_routes(router):
tenant_no=tenant_no,
data=data,
user_id=user_id,
user_info=user_info,
)
return success_response(detail, message="修改成功")
except ValueError as e:
@@ -185,8 +192,9 @@ def register_contract_sub_routes(router):
):
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)
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))
@@ -201,6 +209,7 @@ def register_contract_sub_routes(router):
):
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,
@@ -224,6 +233,7 @@ def register_contract_sub_routes(router):
):
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="撤回成功")
@@ -240,6 +250,7 @@ def register_contract_sub_routes(router):
):
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="执行成功")
@@ -256,6 +267,7 @@ def register_contract_sub_routes(router):
):
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,
@@ -293,6 +305,7 @@ def register_contract_sub_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
query = ContractTemplateListQuery(
pageNum=pageNum,
pageSize=pageSize,
@@ -306,6 +319,7 @@ def register_contract_sub_routes(router):
rows, total = list_contract_templates(
db,
tenant_no,
user_info=user_info,
page=query.pageNum,
page_size=query.pageSize,
filters=query.model_dump(by_alias=True, exclude={"pageNum", "pageSize"}, exclude_none=True),
@@ -333,6 +347,7 @@ def register_contract_sub_routes(router):
):
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:
@@ -348,6 +363,7 @@ def register_contract_sub_routes(router):
):
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(
@@ -371,6 +387,7 @@ def register_contract_sub_routes(router):
):
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")
@@ -380,6 +397,7 @@ def register_contract_sub_routes(router):
tenant_no=tenant_no,
data=data,
user_id=user_id,
user_info=user_info,
)
return success_response(detail, message="修改成功")
except ValueError as e:
@@ -395,8 +413,9 @@ def register_contract_sub_routes(router):
):
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)
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))
@@ -411,6 +430,7 @@ def register_contract_sub_routes(router):
):
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
@@ -429,6 +449,7 @@ def register_contract_sub_routes(router):
):
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
@@ -447,6 +468,7 @@ def register_contract_sub_routes(router):
):
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,
@@ -485,6 +507,7 @@ def register_contract_sub_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
query = ContractApprovalListQuery(
pageNum=pageNum,
pageSize=pageSize,
@@ -526,6 +549,7 @@ def register_contract_sub_routes(router):
):
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:
@@ -595,6 +619,7 @@ def register_contract_sub_routes(router):
):
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,
+44 -1
View File
@@ -10,6 +10,7 @@ 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.quote import (
accept_quote,
create_new_version,
@@ -88,11 +89,13 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
list_body = body or QuoteListBody()
user_id = _user.get("user_id", "") or _user.get("id", "")
rows, total = list_quotes(
db,
tenant_no,
user_info=user_info,
page=list_body.page,
page_size=list_body.pageSize,
filters=list_body.model_dump(by_alias=True, exclude={"page", "pageSize"}),
@@ -122,7 +125,8 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
detail = get_quote_detail(db, body.id, tenant_no=tenant_no)
user_info = crm_user_info(_user)
detail = get_quote_detail(db, body.id, tenant_no=tenant_no, user_info=user_info)
return success_response(detail)
except ValueError as e:
return error_response(400, str(e))
@@ -137,6 +141,7 @@ def register_quote_routes(router):
):
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_quote(
@@ -160,6 +165,7 @@ def register_quote_routes(router):
):
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)
@@ -171,6 +177,7 @@ def register_quote_routes(router):
data=data,
user_id=user_id,
dept_id=dept_id,
user_info=user_info,
)
return success_response(detail, message="修改成功")
except ValueError as e:
@@ -186,6 +193,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
soft_delete_quotes(db, body.ids, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
@@ -201,12 +209,14 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
submit_quote(
db,
body.id,
tenant_no=tenant_no,
approver_ids=body.approverIds,
remark=body.remark,
user_info=user_info,
)
return success_response(None, message="提交成功")
except ValueError as e:
@@ -222,6 +232,7 @@ def register_quote_routes(router):
):
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)
return success_response(None, message="保存成功")
except ValueError as e:
@@ -237,6 +248,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
content = get_template(db, body.id, tenant_no=tenant_no)
return success_response(content or "")
except ValueError as e:
@@ -252,6 +264,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
pdf_url = generate_pdf(db, body.id, tenant_no=tenant_no)
return success_response(pdf_url)
except ValueError as e:
@@ -267,12 +280,14 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
link = generate_share(
db,
body.id,
tenant_no=tenant_no,
validity_days=body.validityDays,
password=body.password or "",
user_info=user_info,
)
return success_response(link)
except ValueError as e:
@@ -288,6 +303,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
accept_quote(db, body.id, tenant_no=tenant_no, remark=body.remark)
return success_response(None, message="操作成功")
except ValueError as e:
@@ -303,12 +319,14 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
reject_quote(
db,
body.id,
tenant_no=tenant_no,
reject_reason=body.rejectReason,
remark=body.remark,
user_info=user_info,
)
return success_response(None, message="操作成功")
except ValueError as e:
@@ -324,6 +342,7 @@ def register_quote_routes(router):
):
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 = to_contract(
@@ -337,6 +356,7 @@ def register_quote_routes(router):
end_date=body.endDate,
user_id=user_id,
dept_id=dept_id,
user_info=user_info,
)
return success_response(contract_id)
except ValueError as e:
@@ -352,6 +372,7 @@ def register_quote_routes(router):
):
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 = create_new_version(
@@ -362,6 +383,7 @@ def register_quote_routes(router):
remark=body.remark,
user_id=user_id,
dept_id=dept_id,
user_info=user_info,
)
return success_response(new_id)
except ValueError as e:
@@ -377,6 +399,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
rows = query_versions(db, body.quoteNo, tenant_no=tenant_no)
return success_response(rows)
except ValueError as e:
@@ -392,6 +415,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
invalid_quote(db, body.id, tenant_no=tenant_no, remark=body.remark)
return success_response(None, message="作废成功")
except ValueError as e:
@@ -407,10 +431,12 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
list_body = body or QuoteListBody()
rows, _ = list_quotes(
db,
tenant_no,
user_info=user_info,
page=1,
page_size=10000,
filters=list_body.model_dump(by_alias=True, exclude={"page", "pageSize"}),
@@ -437,6 +463,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
req = body or QuoteStatisticsOverviewBody()
data = statistics_overview(
db,
@@ -444,6 +471,7 @@ def register_quote_routes(router):
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:
@@ -458,6 +486,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
return success_response(statistics_status(db, tenant_no))
except ValueError as e:
return error_response(400, str(e))
@@ -472,6 +501,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
req = body or QuoteStatisticsTrendBody()
data = statistics_trend(
db,
@@ -479,6 +509,7 @@ def register_quote_routes(router):
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:
@@ -494,6 +525,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
rows = list_quote_products(db, body.quoteId, tenant_no=tenant_no)
return success_response(rows)
except ValueError as e:
@@ -509,6 +541,7 @@ def register_quote_routes(router):
):
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 ""
obj = insert_quote_product(
@@ -534,6 +567,7 @@ def register_quote_routes(router):
):
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)
line_id = data.pop("id")
@@ -543,6 +577,7 @@ def register_quote_routes(router):
tenant_no=tenant_no,
data=data,
user_id=user_id,
user_info=user_info,
)
from app.crud.crm.quote_product import product_row_to_dict
@@ -560,6 +595,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
soft_delete_quote_products(db, body.ids, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
@@ -575,6 +611,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
rows = list_quote_approvals(db, body.quoteId, tenant_no=tenant_no)
return success_response(rows)
except ValueError as e:
@@ -590,6 +627,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
user_id = _user.get("user_id", "") or _user.get("id", "")
approve_quote(
db,
@@ -599,6 +637,7 @@ def register_quote_routes(router):
approval_opinion=body.approvalOpinion or "",
remark=body.remark or "",
user_id=user_id,
user_info=user_info,
)
return success_response(None, message="审批成功")
except ValueError as e:
@@ -614,6 +653,7 @@ def register_quote_routes(router):
):
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_approval(
db,
@@ -621,6 +661,7 @@ def register_quote_routes(router):
tenant_no=tenant_no,
remark=body.remark or "",
user_id=user_id,
user_info=user_info,
)
return success_response(None, message="撤回成功")
except ValueError as e:
@@ -651,6 +692,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
rows = list_share_logs(db, body.quoteId, tenant_no=tenant_no)
return success_response(rows)
except ValueError as e:
@@ -666,6 +708,7 @@ def register_quote_routes(router):
):
try:
tenant_no = get_tenant_no(db, _user)
user_info = crm_user_info(_user)
stats = share_log_statistics(db, body.quoteId, tenant_no=tenant_no)
return success_response(stats)
except ValueError as e: