feat: 全模块公司隔离 + crossDomain权限码动态跨域控制
- get_current_company_filter: 新增_has_cross_domain_permission, 权限码替代硬编码 - 补全11个Service的get_current_company_filter调用(semi/product/service/outbound/bom/trans/scrap/summary) - base/search修复: search_material此前无隔离, 已补全 - get_current_company_filter兜底: JWT缺company_name时返回__NO_COMPANY__防止放行 - permission.py: _get_operator_company补全返回值, 修复权限页保存逻辑 - 新增crossDomain迁移脚本, element_type=element挂system_mgmt下
This commit is contained in:
@ -14,6 +14,7 @@ def get_list():
|
||||
start_date = request.args.get('start_date')
|
||||
end_date = request.args.get('end_date')
|
||||
source_type = request.args.get('source_type') # 可选:筛选 specific table
|
||||
company = request.args.get('company', '')
|
||||
|
||||
result = InboundSummaryService.get_list(
|
||||
page=page,
|
||||
@ -21,7 +22,8 @@ def get_list():
|
||||
keyword=keyword,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
source_type=source_type
|
||||
source_type=source_type,
|
||||
company=company
|
||||
)
|
||||
|
||||
return jsonify({
|
||||
@ -47,13 +49,15 @@ def export_data():
|
||||
start_date = request.args.get('start_date')
|
||||
end_date = request.args.get('end_date')
|
||||
source_type = request.args.get('source_type')
|
||||
company = request.args.get('company', '')
|
||||
|
||||
# 调用导出服务
|
||||
file_stream = InboundSummaryService.export_excel(
|
||||
keyword=keyword,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
source_type=source_type
|
||||
source_type=source_type,
|
||||
company=company
|
||||
)
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
@ -179,10 +179,10 @@ def get_outbound_list():
|
||||
limit = int(request.args.get('limit', 10))
|
||||
keyword = request.args.get('keyword', '')
|
||||
search_type = request.args.get('search_type', 'all')
|
||||
# 如果前端传了日期范围,可以解析处理,这里暂略
|
||||
company = request.args.get('company', '')
|
||||
|
||||
# ★ [修改] 调用分组查询服务,支持搜索类型
|
||||
result = OutboundService.get_grouped_list(page, limit, keyword, search_type=search_type)
|
||||
result = OutboundService.get_grouped_list(page, limit, keyword, search_type=search_type, company=company)
|
||||
|
||||
# 字段级脱敏
|
||||
user_permissions = get_current_user_permissions()
|
||||
|
||||
@ -8,11 +8,12 @@ permission_bp = Blueprint('permission', __name__)
|
||||
|
||||
|
||||
def _get_operator_company():
|
||||
"""从 JWT 获取当前操作者公司(None=超管)"""
|
||||
"""从 JWT 获取当前操作者公司(None=超管,具体值=该角色所属公司)"""
|
||||
claims = get_jwt()
|
||||
role = claims.get('role', '')
|
||||
if role and role.upper() == 'SUPER_ADMIN':
|
||||
return None # 超管不限制公司
|
||||
return claims.get('company_name', '')
|
||||
|
||||
|
||||
def _has_system_permission(role_code):
|
||||
@ -24,7 +25,6 @@ def _has_system_permission(role_code):
|
||||
return 'system_permission' in all_perms
|
||||
except Exception:
|
||||
return False
|
||||
return claims.get('company_name', '')
|
||||
|
||||
|
||||
@permission_bp.route('/tree', methods=['GET'])
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# inventory-backend/app/api/v1/scrap.py
|
||||
from flask import Blueprint, request, jsonify
|
||||
from flask_jwt_extended import jwt_required, get_jwt_identity, get_jwt
|
||||
from app.utils.decorators import permission_required, audit_log
|
||||
from app.utils.decorators import permission_required, audit_log, get_current_company_filter
|
||||
from app.services.auth_service import AuthService
|
||||
from app.extensions import db
|
||||
from app.models.transaction import TransScrap, TransRepair
|
||||
@ -322,6 +322,37 @@ class ScrapService:
|
||||
if end_date:
|
||||
query = query.filter(TransScrap.operation_time <= end_date + ' 23:59:59')
|
||||
|
||||
# 【行级数据隔离】基于 JWT 多租户公司过滤
|
||||
# 通过 stock 表或 trans_repair 关联到 MaterialBase
|
||||
company_limit = get_current_company_filter()
|
||||
if company_limit is not None:
|
||||
buy_subq = db.session.query(TransScrap.id).join(
|
||||
StockBuy, db.and_(TransScrap.stock_id == StockBuy.id,
|
||||
TransScrap.source_table == 'stock_buy')
|
||||
).join(MaterialBase, StockBuy.base_id == MaterialBase.id).filter(
|
||||
MaterialBase.company_name == company_limit
|
||||
)
|
||||
semi_subq = db.session.query(TransScrap.id).join(
|
||||
StockSemi, db.and_(TransScrap.stock_id == StockSemi.id,
|
||||
TransScrap.source_table == 'stock_semi')
|
||||
).join(MaterialBase, StockSemi.base_id == MaterialBase.id).filter(
|
||||
MaterialBase.company_name == company_limit
|
||||
)
|
||||
product_subq = db.session.query(TransScrap.id).join(
|
||||
StockProduct, db.and_(TransScrap.stock_id == StockProduct.id,
|
||||
TransScrap.source_table == 'stock_product')
|
||||
).join(MaterialBase, StockProduct.base_id == MaterialBase.id).filter(
|
||||
MaterialBase.company_name == company_limit
|
||||
)
|
||||
repair_subq = db.session.query(TransScrap.id).join(
|
||||
TransRepair, db.and_(TransScrap.stock_id == TransRepair.id,
|
||||
TransScrap.source_table == 'trans_repair')
|
||||
).join(MaterialBase, TransRepair.base_id == MaterialBase.id).filter(
|
||||
MaterialBase.company_name == company_limit
|
||||
)
|
||||
all_matches = buy_subq.union(semi_subq, product_subq, repair_subq).subquery()
|
||||
query = query.filter(TransScrap.id.in_(all_matches))
|
||||
|
||||
# 按时间倒序
|
||||
query = query.order_by(TransScrap.operation_time.desc())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user