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:
@ -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. 采购申请列表
|
# 1. 采购申请列表
|
||||||
# GET /api/v1/purchase
|
# GET /api/v1/purchase
|
||||||
@ -58,6 +77,10 @@ def get_purchase_list():
|
|||||||
status=status
|
status=status
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ★ 字段级价格过滤
|
||||||
|
for item in (result.get('items') or []):
|
||||||
|
_filter_purchase_prices(item)
|
||||||
|
|
||||||
return jsonify({'code': 200, 'msg': '获取成功', 'data': result})
|
return jsonify({'code': 200, 'msg': '获取成功', 'data': result})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
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():
|
if purchase['requester_id'] != user_id and not _user_has_purchase_perm():
|
||||||
return jsonify({'code': 403, 'msg': '无权查看此申请'}), 403
|
return jsonify({'code': 403, 'msg': '无权查看此申请'}), 403
|
||||||
|
|
||||||
|
_filter_purchase_prices(purchase)
|
||||||
return jsonify({'code': 200, 'msg': '获取成功', 'data': purchase}), 200
|
return jsonify({'code': 200, 'msg': '获取成功', 'data': purchase}), 200
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({'code': 500, 'msg': str(e)}), 500
|
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
|
page=page, per_page=per_page, keyword=keyword
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ★ 注意:不在此处过滤价格。此端点用于按单入库,
|
||||||
|
# 价格数据需随响应传递到入库表单(前端通过 inbound_buy:unit_price 权限控制写入)
|
||||||
return jsonify({'code': 200, 'msg': '获取成功', 'data': result}), 200
|
return jsonify({'code': 200, 'msg': '获取成功', 'data': result}), 200
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|||||||
@ -638,19 +638,23 @@ class PermissionService:
|
|||||||
db.session.add(new_perm)
|
db.session.add(new_perm)
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
# ★ 采购申请操作权限元素
|
# ★ 采购申请权限元素
|
||||||
purchase_op = SysElement.query.filter_by(
|
purchase_elements = [
|
||||||
menu_code='inbound_purchase',
|
('inbound_purchase:operation', '可编辑', 'operation'),
|
||||||
code='inbound_purchase:operation'
|
('inbound_purchase:unit_price', '采购单价', 'column'),
|
||||||
).first()
|
('inbound_purchase:total_price', '采购总价', 'column'),
|
||||||
if not purchase_op:
|
('inbound_purchase:tax_rate', '税率', 'column'),
|
||||||
db.session.add(SysElement(
|
]
|
||||||
menu_code='inbound_purchase',
|
for code, name, etype in purchase_elements:
|
||||||
name='可编辑',
|
existing = SysElement.query.filter_by(
|
||||||
code='inbound_purchase:operation',
|
menu_code='inbound_purchase', code=code
|
||||||
element_type='operation'
|
).first()
|
||||||
))
|
if not existing:
|
||||||
print(f"✅ 采购申请操作权限元素已创建")
|
db.session.add(SysElement(
|
||||||
|
menu_code='inbound_purchase', name=name,
|
||||||
|
code=code, element_type=etype
|
||||||
|
))
|
||||||
|
print(f"✅ 采购申请元素已创建: {code}")
|
||||||
|
|
||||||
print(f"✅ 所有菜单初始化完成")
|
print(f"✅ 所有菜单初始化完成")
|
||||||
return True
|
return True
|
||||||
|
|||||||
@ -24,17 +24,17 @@
|
|||||||
<el-table-column prop="spec_model" label="规格型号" min-width="120" show-overflow-tooltip />
|
<el-table-column prop="spec_model" label="规格型号" min-width="120" show-overflow-tooltip />
|
||||||
<el-table-column prop="quantity" label="数量" width="80" align="center" />
|
<el-table-column prop="quantity" label="数量" width="80" align="center" />
|
||||||
<el-table-column prop="purchase_date" label="采购日期" width="110" />
|
<el-table-column prop="purchase_date" label="采购日期" width="110" />
|
||||||
<el-table-column label="含税单价" width="110" align="right">
|
<el-table-column v-if="userStore.hasPermission('inbound_purchase:unit_price')" label="含税单价" width="110" align="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.unit_price ? '¥' + Number(row.unit_price).toFixed(2) : '-' }}
|
{{ row.unit_price ? '¥' + Number(row.unit_price).toFixed(2) : '-' }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="含税总价" width="120" align="right">
|
<el-table-column v-if="userStore.hasPermission('inbound_purchase:total_price')" label="含税总价" width="120" align="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.total_price ? '¥' + Number(row.total_price).toFixed(2) : '-' }}
|
{{ row.total_price ? '¥' + Number(row.total_price).toFixed(2) : '-' }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="tax_rate" label="税率" width="70" align="center">
|
<el-table-column v-if="userStore.hasPermission('inbound_purchase:tax_rate')" prop="tax_rate" label="税率" width="70" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.tax_rate != null ? row.tax_rate + '%' : '-' }}
|
{{ row.tax_rate != null ? row.tax_rate + '%' : '-' }}
|
||||||
</template>
|
</template>
|
||||||
@ -200,8 +200,8 @@
|
|||||||
<el-descriptions-item label="规格型号">{{ detail.spec_model || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="规格型号">{{ detail.spec_model || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="采购数量">{{ detail.quantity }}</el-descriptions-item>
|
<el-descriptions-item label="采购数量">{{ detail.quantity }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="采购日期">{{ detail.purchase_date }}</el-descriptions-item>
|
<el-descriptions-item label="采购日期">{{ detail.purchase_date }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="单价">{{ detail.unit_price || '-' }}</el-descriptions-item>
|
<el-descriptions-item v-if="userStore.hasPermission('inbound_purchase:unit_price')" label="单价">{{ detail.unit_price || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="总价">{{ detail.total_price || '-' }}</el-descriptions-item>
|
<el-descriptions-item v-if="userStore.hasPermission('inbound_purchase:total_price')" label="总价">{{ detail.total_price || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="申请人">{{ detail.requester_name }}</el-descriptions-item>
|
<el-descriptions-item label="申请人">{{ detail.requester_name }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="审批人">{{ detail.approver_name || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="审批人">{{ detail.approver_name || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="审批时间">{{ detail.approved_at || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="审批时间">{{ detail.approved_at || '-' }}</el-descriptions-item>
|
||||||
|
|||||||
Reference in New Issue
Block a user