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:
@ -48,6 +48,12 @@ class MaterialBaseService:
|
||||
)
|
||||
)
|
||||
|
||||
# 【行级数据隔离】基于 JWT 多租户公司过滤
|
||||
from app.utils.decorators import get_current_company_filter
|
||||
company_limit = get_current_company_filter()
|
||||
if company_limit is not None:
|
||||
query = query.filter(MaterialBase.company_name == company_limit)
|
||||
|
||||
# [修改1] 增加返回数量限制
|
||||
# 原为 limit(20),现改为 1000,确保前端能获取所有(或足够多)的数据
|
||||
query = query.limit(1000)
|
||||
|
||||
@ -15,7 +15,7 @@ from openpyxl.utils import get_column_letter
|
||||
class InboundSummaryService:
|
||||
|
||||
@staticmethod
|
||||
def get_list(page=1, per_page=10, keyword=None, start_date=None, end_date=None, source_type=None):
|
||||
def get_list(page=1, per_page=10, keyword=None, start_date=None, end_date=None, source_type=None, company=None):
|
||||
"""
|
||||
聚合查询:
|
||||
1. 联合 StockBuy, StockSemi, StockProduct 三张表
|
||||
@ -126,6 +126,10 @@ class InboundSummaryService:
|
||||
if source_type:
|
||||
query = query.filter(cte.c.source_type == source_type)
|
||||
|
||||
# 公司过滤(跨域选择器传入)
|
||||
if company:
|
||||
query = query.filter(MaterialBase.company_name == company)
|
||||
|
||||
# =========================================================
|
||||
# 5. 获取总数
|
||||
# =========================================================
|
||||
@ -139,6 +143,8 @@ class InboundSummaryService:
|
||||
count_query = count_query.filter(cte.c.inbound_date.between(start_date, end_date))
|
||||
if source_type:
|
||||
count_query = count_query.filter(cte.c.source_type == source_type)
|
||||
if company:
|
||||
count_query = count_query.filter(MaterialBase.company_name == company)
|
||||
|
||||
total = count_query.scalar() or 0
|
||||
|
||||
@ -218,7 +224,7 @@ class InboundSummaryService:
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def export_excel(keyword=None, start_date=None, end_date=None, source_type=None):
|
||||
def export_excel(keyword=None, start_date=None, end_date=None, source_type=None, company=None):
|
||||
"""
|
||||
导出入库记录 Excel
|
||||
"""
|
||||
@ -304,6 +310,9 @@ class InboundSummaryService:
|
||||
if source_type:
|
||||
query = query.filter(cte.c.source_type == source_type)
|
||||
|
||||
if company:
|
||||
query = query.filter(MaterialBase.company_name == company)
|
||||
|
||||
# 排序
|
||||
query = query.order_by(desc(cte.c.inbound_date), asc(cte.c.sku))
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# app/services/inbound/product_service.py
|
||||
from app.extensions import db
|
||||
from app.models.base import MaterialBase
|
||||
from app.utils.decorators import get_current_company_filter
|
||||
from app.models.inbound.buy import StockBuy
|
||||
from app.models.inbound.semi import StockSemi
|
||||
from app.models.outbound import TransOutbound
|
||||
@ -363,6 +364,13 @@ class ProductInboundService:
|
||||
if material_type and material_type.strip():
|
||||
query = query.filter(MaterialBase.material_type == material_type.strip())
|
||||
|
||||
# ============================================================
|
||||
# 【行级数据隔离】基于 JWT 多租户公司过滤
|
||||
# ============================================================
|
||||
company_limit = get_current_company_filter()
|
||||
if company_limit is not None:
|
||||
query = query.filter(MaterialBase.company_name == company_limit)
|
||||
|
||||
# ============================================================
|
||||
# 【全局特权】基于 JWT 与 global:cross_company_op 的跨组织隔离
|
||||
# ============================================================
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# app/services/inbound/semi_service.py
|
||||
from app.extensions import db
|
||||
from app.models.base import MaterialBase
|
||||
from app.utils.decorators import get_current_company_filter
|
||||
from app.models.inbound.buy import StockBuy
|
||||
from app.models.inbound.product import StockProduct
|
||||
from app.models.outbound import TransOutbound
|
||||
@ -453,6 +454,13 @@ class SemiInboundService:
|
||||
if material_type and material_type.strip():
|
||||
query = query.filter(MaterialBase.material_type == material_type.strip())
|
||||
|
||||
# ============================================================
|
||||
# 【行级数据隔离】基于 JWT 多租户公司过滤
|
||||
# ============================================================
|
||||
company_limit = get_current_company_filter()
|
||||
if company_limit is not None:
|
||||
query = query.filter(MaterialBase.company_name == company_limit)
|
||||
|
||||
# ============================================================
|
||||
# 【全局特权】基于 JWT 与 global:cross_company_op 的跨组织隔离
|
||||
# ============================================================
|
||||
|
||||
@ -158,9 +158,13 @@ class ServiceService:
|
||||
try:
|
||||
query = StockService.query.filter_by(is_deleted=False)
|
||||
|
||||
# 始终 join MaterialBase(base_id 为 NOT NULL,inner join 不会改变结果行数)
|
||||
# 用于公司过滤和关键词搜索
|
||||
query = query.join(StockService.base)
|
||||
|
||||
# 关键词联表搜索
|
||||
if keyword:
|
||||
query = query.join(StockService.base).filter(
|
||||
query = query.filter(
|
||||
db.or_(
|
||||
StockService.sku.ilike(f'%{keyword}%'),
|
||||
MaterialBase.name.ilike(f'%{keyword}%'),
|
||||
@ -168,6 +172,13 @@ class ServiceService:
|
||||
)
|
||||
)
|
||||
|
||||
# 【行级数据隔离】基于 JWT 多租户公司过滤
|
||||
from app.utils.decorators import get_current_company_filter
|
||||
|
||||
company_limit = get_current_company_filter()
|
||||
if company_limit is not None:
|
||||
query = query.filter(MaterialBase.company_name == company_limit)
|
||||
|
||||
# 日期过滤
|
||||
if start_date:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user