feat: 采购模块重构 — 权限驱动的可见性 + 严格操作权限

## purchase.py
- GET /purchase (列表): @jwt_required, 有权限看同公司全部/无权限只看自己
- POST /purchase (创建): @jwt_required, 任何登录用户可提交
- GET /purchase/<id> (详情): @jwt_required, 自己的或有权者可见
- PATCH /purchase/<id>/approve (审批): @permission_required('inbound_purchase:operation')
  不再硬编码 SUPERVISOR 角色, 有操作权限即可审批
- GET /purchase/approvers, /auto-fill, /search-material: @jwt_required (开放给创建流程)
- 新增 _user_has_purchase_perm() 统一权限检查
- 移除所有硬编码 role in ('SUPERVISOR','SUPER_ADMIN')

## purchase_service.py
- send_email → send_email_async (采购审批邮件异步发送)

## purchase/index.vue
- canApprove: 仅检查 inbound_purchase:operation (菜单权限≠审批权限)
- customUpload: 修复 v-model:file-list 重复推入导致图片双份显示
- auth.py → purchase.py 权限前缀统一
This commit is contained in:
yueli
2026-07-16 11:25:53 +08:00
parent 0b75740ae0
commit 128985af17
3 changed files with 187 additions and 145 deletions

View File

@ -128,7 +128,7 @@ class PurchaseService:
@staticmethod
def get_purchase_list(page=1, per_page=20, requester_id=None, status=None):
"""获取采购申请列表,普通用户只看自己的,主管/超管看全部"""
"""获取采购申请列表,普通用户只看自己的,主管/超管看同公司全部"""
from app.utils.decorators import get_current_company_filter
from app.models.system import SysUser
from sqlalchemy import or_
@ -141,7 +141,7 @@ class PurchaseService:
if status is not None:
query = query.filter(PurchaseRequest.status == status)
# 【行级数据隔离】通过 base_id→MaterialBase 或 requester_id→SysUser 双重过滤
# 【行级数据隔离】同公司可见:匹配 MaterialBase.company_name 或 SysUser.department
company_limit = get_current_company_filter()
if company_limit is not None:
query = query.outerjoin(MaterialBase, PurchaseRequest.base_id == MaterialBase.id) \
@ -298,7 +298,7 @@ class PurchaseService:
def _notify_new_request(purchase):
"""发送新申请邮件给审批人"""
try:
from app.utils.email_service import send_email
from app.utils.email_service import send_email_async
from app.models.system import SysUser
if not purchase.approver_id:
@ -324,7 +324,7 @@ class PurchaseService:
此邮件由系统自动发送,请勿回复。
"""
send_email(approver.email, subject, content)
send_email_async(approver.email, subject, content)
except Exception as e:
try:
from flask import current_app
@ -336,7 +336,7 @@ class PurchaseService:
def _notify_approved(purchase):
"""审批通过后通知申请人"""
try:
from app.utils.email_service import send_email
from app.utils.email_service import send_email_async
from app.models.system import SysUser
requester = db.session.get(SysUser, purchase.requester_id)
@ -352,7 +352,7 @@ class PurchaseService:
此邮件由系统自动发送,请勿回复。
"""
send_email(requester.email, subject, content)
send_email_async(requester.email, subject, content)
except Exception as e:
try:
from flask import current_app
@ -364,7 +364,7 @@ class PurchaseService:
def _notify_rejected(purchase):
"""审批驳回后通知申请人"""
try:
from app.utils.email_service import send_email
from app.utils.email_service import send_email_async
from app.models.system import SysUser
requester = db.session.get(SysUser, purchase.requester_id)
@ -382,6 +382,6 @@ class PurchaseService:
此邮件由系统自动发送,请勿回复。
"""
send_email(requester.email, subject, content)
send_email_async(requester.email, subject, content)
except Exception as e:
print(f"[Email] 采购申请驳回通知失败: {e}")