feat: 采购申请字段级价格权限 — 库管看不到采购价格

## permission_service.py
- init_all_menus: 新增3个采购权限元素
  inbound_purchase:unit_price, :total_price, :tax_rate

## purchase.py
- _filter_purchase_prices(): 无价格权限则pop价格字段
- GET /purchase (列表): 应用价格过滤
- GET /purchase/<id> (详情): 应用价格过滤
- approved-unstocked: 保留价格(入库数据源,前端按inbound_buy权限控制)

## purchase/index.vue
- 列表: 单价/总价/税率列 v-if hasPermission
- 详情: 单价/总价 v-if hasPermission
This commit is contained in:
yueli
2026-07-16 17:34:24 +08:00
parent 6e064064d5
commit 754c46bd59
3 changed files with 48 additions and 18 deletions

View File

@ -34,6 +34,25 @@ def _user_has_purchase_perm():
)
def _filter_purchase_prices(item_dict):
"""Fail-Closed: 无价格权限则剥离采购价格字段"""
from app.services.auth_service import AuthService
claims = get_jwt()
role = claims.get('role', '')
if role.upper() in ('SUPER_ADMIN', 'SUPERVISOR'):
return
perm_dict = AuthService.get_user_permissions(role, company_name=claims.get('company_name', ''))
all_perms = perm_dict.get('menus', []) + perm_dict.get('elements', [])
if 'inbound_purchase:unit_price' not in all_perms:
item_dict.pop('unit_price', None)
item_dict.pop('pre_tax_unit_price', None)
item_dict.pop('post_tax_unit_price', None)
if 'inbound_purchase:total_price' not in all_perms:
item_dict.pop('total_price', None)
if 'inbound_purchase:tax_rate' not in all_perms:
item_dict.pop('tax_rate', None)
# --------------------------------------------------------
# 1. 采购申请列表
# GET /api/v1/purchase
@ -58,6 +77,10 @@ def get_purchase_list():
status=status
)
# ★ 字段级价格过滤
for item in (result.get('items') or []):
_filter_purchase_prices(item)
return jsonify({'code': 200, 'msg': '获取成功', 'data': result})
except Exception as e:
traceback.print_exc()
@ -128,6 +151,7 @@ def get_purchase_detail(purchase_id):
if purchase['requester_id'] != user_id and not _user_has_purchase_perm():
return jsonify({'code': 403, 'msg': '无权查看此申请'}), 403
_filter_purchase_prices(purchase)
return jsonify({'code': 200, 'msg': '获取成功', 'data': purchase}), 200
except Exception as e:
return jsonify({'code': 500, 'msg': str(e)}), 500
@ -241,6 +265,8 @@ def get_approved_unstocked_requests():
page=page, per_page=per_page, keyword=keyword
)
# ★ 注意:不在此处过滤价格。此端点用于按单入库,
# 价格数据需随响应传递到入库表单(前端通过 inbound_buy:unit_price 权限控制写入)
return jsonify({'code': 200, 'msg': '获取成功', 'data': result}), 200
except Exception as e:
traceback.print_exc()