fix: refactor advanced filters to use WHERE for subquery columns and rewrite warning sort in pure order_by expressions
This commit is contained in:
@ -230,12 +230,12 @@ class MaterialBaseService:
|
|||||||
.outerjoin(MaterialWarningSetting, MaterialBase.id == MaterialWarningSetting.base_id)
|
.outerjoin(MaterialWarningSetting, MaterialBase.id == MaterialWarningSetting.base_id)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 【修复3】高级筛选:聚合字段使用 HAVING,非聚合字段使用 WHERE
|
# 【修复3】高级筛选:统一使用 WHERE (filter)
|
||||||
|
# 聚合字段同样是子查询列,直接用 filter 过滤即可
|
||||||
# ============================================================
|
# ============================================================
|
||||||
advanced_filters = filters.get('advancedFilters', []) if filters else []
|
advanced_filters = filters.get('advancedFilters', []) if filters else []
|
||||||
having_conditions = []
|
|
||||||
filter_conditions = []
|
filter_conditions = []
|
||||||
|
|
||||||
if advanced_filters:
|
if advanced_filters:
|
||||||
allowed_fields = {
|
allowed_fields = {
|
||||||
'companyName': 'company_name',
|
'companyName': 'company_name',
|
||||||
@ -248,9 +248,9 @@ class MaterialBaseService:
|
|||||||
'inventoryCount': 'total_inv',
|
'inventoryCount': 'total_inv',
|
||||||
'availableCount': 'total_avail'
|
'availableCount': 'total_avail'
|
||||||
}
|
}
|
||||||
# 聚合字段列表(这些需要用 HAVING)
|
# 聚合字段列表
|
||||||
aggregate_fields = {'inventoryCount', 'availableCount'}
|
aggregate_fields = {'inventoryCount', 'availableCount'}
|
||||||
|
|
||||||
field_permission_map = {
|
field_permission_map = {
|
||||||
'companyName': 'material_list:companyName',
|
'companyName': 'material_list:companyName',
|
||||||
'name': 'material_list:name',
|
'name': 'material_list:name',
|
||||||
@ -262,18 +262,18 @@ class MaterialBaseService:
|
|||||||
'inventoryCount': 'material_list:inventoryCount',
|
'inventoryCount': 'material_list:inventoryCount',
|
||||||
'availableCount': 'material_list:availableCount'
|
'availableCount': 'material_list:availableCount'
|
||||||
}
|
}
|
||||||
|
|
||||||
for condition in advanced_filters:
|
for condition in advanced_filters:
|
||||||
field = condition.get('field')
|
field = condition.get('field')
|
||||||
operator = condition.get('operator')
|
operator = condition.get('operator')
|
||||||
value = condition.get('value')
|
value = condition.get('value')
|
||||||
if not field or not operator or value is None:
|
if not field or not operator or value is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
db_field = allowed_fields.get(field)
|
db_field = allowed_fields.get(field)
|
||||||
if not db_field:
|
if not db_field:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 权限校验
|
# 权限校验
|
||||||
if user_permissions is not None:
|
if user_permissions is not None:
|
||||||
perm_code = field_permission_map.get(field)
|
perm_code = field_permission_map.get(field)
|
||||||
@ -281,32 +281,32 @@ class MaterialBaseService:
|
|||||||
pass
|
pass
|
||||||
elif perm_code and perm_code not in user_permissions:
|
elif perm_code and perm_code not in user_permissions:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 判断是否为聚合字段
|
# 判断是否为聚合字段
|
||||||
is_aggregate = field in aggregate_fields
|
is_aggregate = field in aggregate_fields
|
||||||
|
|
||||||
if is_aggregate:
|
if is_aggregate:
|
||||||
# 聚合字段:使用 HAVING - 通过子查询列进行比较
|
# 聚合字段:直接使用子查询列,通过 WHERE (filter) 过滤
|
||||||
col = inner_sub.c.total_inv if field == 'inventoryCount' else inner_sub.c.total_avail
|
col = inner_sub.c.total_inv if field == 'inventoryCount' else inner_sub.c.total_avail
|
||||||
try:
|
try:
|
||||||
num_val = float(value)
|
num_val = float(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if operator == 'eq':
|
if operator == 'eq':
|
||||||
having_conditions.append(col == num_val)
|
filter_conditions.append(col == num_val)
|
||||||
elif operator == 'ne':
|
elif operator == 'ne':
|
||||||
having_conditions.append(col != num_val)
|
filter_conditions.append(col != num_val)
|
||||||
elif operator == 'ge':
|
elif operator == 'ge':
|
||||||
having_conditions.append(col >= num_val)
|
filter_conditions.append(col >= num_val)
|
||||||
elif operator == 'le':
|
elif operator == 'le':
|
||||||
having_conditions.append(col <= num_val)
|
filter_conditions.append(col <= num_val)
|
||||||
else:
|
else:
|
||||||
# 非聚合字段:使用 WHERE
|
# 非聚合字段:使用 WHERE
|
||||||
column = getattr(MaterialBase, db_field, None)
|
column = getattr(MaterialBase, db_field, None)
|
||||||
if column is None:
|
if column is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if operator == 'eq':
|
if operator == 'eq':
|
||||||
filter_conditions.append(column == value)
|
filter_conditions.append(column == value)
|
||||||
elif operator == 'ne':
|
elif operator == 'ne':
|
||||||
@ -325,14 +325,10 @@ class MaterialBaseService:
|
|||||||
filter_conditions.append(column <= num_val)
|
filter_conditions.append(column <= num_val)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 应用 WHERE 条件
|
# 应用 WHERE 条件(统一使用 filter)
|
||||||
if filter_conditions:
|
if filter_conditions:
|
||||||
query = query.filter(and_(*filter_conditions))
|
query = query.filter(and_(*filter_conditions))
|
||||||
|
|
||||||
# 应用 HAVING 条件(聚合字段筛选)
|
|
||||||
if having_conditions:
|
|
||||||
query = query.having(and_(*having_conditions))
|
|
||||||
|
|
||||||
# 排序处理(支持全字段)
|
# 排序处理(支持全字段)
|
||||||
order_by_column = filters.get('orderByColumn', '')
|
order_by_column = filters.get('orderByColumn', '')
|
||||||
@ -342,9 +338,8 @@ class MaterialBaseService:
|
|||||||
enable_warning_sort = filters.get('enableWarningSort', False)
|
enable_warning_sort = filters.get('enableWarningSort', False)
|
||||||
|
|
||||||
if enable_warning_sort:
|
if enable_warning_sort:
|
||||||
print("====== [DEBUG] 成功进入预警强排逻辑 (SQLA 2.0) ======")
|
print("====== [DEBUG] 成功进入预警强排逻辑 ======")
|
||||||
# 【核心修复】使用子查询列进行预警排序计算
|
# 直接在 order_by 中进行计算排序,不污染 select 列
|
||||||
# total_inv 现在是 inner_sub.c.total_inv,可以安全参与 case 计算
|
|
||||||
inv_val = inner_sub.c.total_inv
|
inv_val = inner_sub.c.total_inv
|
||||||
red_val = cast(MaterialWarningSetting.red_threshold, Numeric)
|
red_val = cast(MaterialWarningSetting.red_threshold, Numeric)
|
||||||
yellow_val = cast(MaterialWarningSetting.yellow_threshold, Numeric)
|
yellow_val = cast(MaterialWarningSetting.yellow_threshold, Numeric)
|
||||||
@ -354,26 +349,24 @@ class MaterialBaseService:
|
|||||||
(and_(MaterialWarningSetting.is_enabled.is_(True), inv_val <= red_val), 2),
|
(and_(MaterialWarningSetting.is_enabled.is_(True), inv_val <= red_val), 2),
|
||||||
(and_(MaterialWarningSetting.is_enabled.is_(True), inv_val <= yellow_val), 1),
|
(and_(MaterialWarningSetting.is_enabled.is_(True), inv_val <= yellow_val), 1),
|
||||||
else_=0
|
else_=0
|
||||||
).label('sort_level')
|
)
|
||||||
|
# 红色预警时的缺口
|
||||||
# 红色预警时的缺口(库存与红色阈值的差距)
|
|
||||||
red_shortage = case(
|
red_shortage = case(
|
||||||
(and_(MaterialWarningSetting.is_enabled.is_(True), inv_val <= red_val), red_val - inv_val),
|
(and_(MaterialWarningSetting.is_enabled.is_(True), inv_val <= red_val), red_val - inv_val),
|
||||||
else_=0
|
else_=0
|
||||||
).label('sort_red')
|
)
|
||||||
|
|
||||||
# 黄色预警时的缺口
|
# 黄色预警时的缺口
|
||||||
yellow_distance = case(
|
yellow_distance = case(
|
||||||
(and_(MaterialWarningSetting.is_enabled.is_(True), inv_val > red_val, inv_val <= yellow_val), inv_val - red_val),
|
(and_(MaterialWarningSetting.is_enabled.is_(True), inv_val > red_val, inv_val <= yellow_val), inv_val - red_val),
|
||||||
else_=999999
|
else_=999999
|
||||||
).label('sort_yellow')
|
)
|
||||||
|
|
||||||
query = query.add_columns(warning_level, red_shortage, yellow_distance)
|
# 直接在 order_by 中使用 case() 表达式
|
||||||
query = query.order_by(None).order_by(
|
query = query.order_by(
|
||||||
text("sort_level DESC"),
|
desc(warning_level),
|
||||||
text("sort_red DESC"),
|
desc(red_shortage),
|
||||||
text("sort_yellow ASC"),
|
asc(yellow_distance),
|
||||||
MaterialBase.id.desc()
|
desc(MaterialBase.id)
|
||||||
)
|
)
|
||||||
elif order_by_column:
|
elif order_by_column:
|
||||||
# 字段映射 - 使用子查询列进行排序
|
# 字段映射 - 使用子查询列进行排序
|
||||||
|
|||||||
Reference in New Issue
Block a user