\"fix: improve warning sort logic - red group by shortage desc, yellow group by safety distance asc\"

This commit is contained in:
DXC
2026-03-11 17:17:10 +08:00
parent 4bf5a23d31
commit 404577e6b5

View File

@ -1,12 +1,12 @@
# 文件路径: app/services/inbound/base_service.py # 文件路径: app/services/inbound/base_service.py
from app.extensions import db from app.extensions import db
from app.models.base import MaterialBase from app.models.base import MaterialBase, MaterialWarningSetting
from app.models.inbound.buy import StockBuy from app.models.inbound.buy import StockBuy
from app.models.inbound.semi import StockSemi from app.models.inbound.semi import StockSemi
from app.models.inbound.product import StockProduct from app.models.inbound.product import StockProduct
# from app.models.inbound.service import StockService # from app.models.inbound.service import StockService
from sqlalchemy import or_, and_, func from sqlalchemy import or_, and_, func, case, desc, asc
import traceback import traceback
import json import json
import io import io
@ -314,56 +314,33 @@ class MaterialBaseService:
if enable_warning_sort: if enable_warning_sort:
# 预警智能排序:先按预警状态排序,再按缺口/余量排序 # 预警智能排序:先按预警状态排序,再按缺口/余量排序
# 使用 CASE 表达式计算预警状态 # 状态层级:红(2) > 黄(1) > 常规(0)
# 状态: 2=红(库存<=red), 1=黄(red<库存<=yellow), 0=正常/未开启 warning_level = case(
from sqlalchemy import case (and_(MaterialWarningSetting.is_enabled == True, total_inv <= MaterialWarningSetting.red_threshold), 2),
(and_(MaterialWarningSetting.is_enabled == True, total_inv <= MaterialWarningSetting.yellow_threshold), 1),
# 计算预警状态
warning_status = case(
(
(MaterialWarningSetting.is_enabled == True) &
(total_inv <= MaterialWarningSetting.red_threshold),
2 # 红色预警
),
(
(MaterialWarningSetting.is_enabled == True) &
(total_inv > MaterialWarningSetting.red_threshold) &
(total_inv <= MaterialWarningSetting.yellow_threshold),
1 # 黄色预警
),
else_=0 # 正常或未开启
).label('warning_status')
# 红色组内部:按缺口降序 (red_threshold - inventory)
red_gap = case(
(
(MaterialWarningSetting.is_enabled == True) &
(total_inv <= MaterialWarningSetting.red_threshold),
MaterialWarningSetting.red_threshold - total_inv
),
else_=0 else_=0
).label('red_gap') )
# 色组内部:按余量升序 (inventory - red_threshold),离红线越近越靠前 # 色组内部:缺口越大越靠前 (red_threshold - total_inv) DESC
yellow_gap = case( red_shortage = case(
( (and_(MaterialWarningSetting.is_enabled == True, total_inv <= MaterialWarningSetting.red_threshold),
(MaterialWarningSetting.is_enabled == True) & MaterialWarningSetting.red_threshold - total_inv),
(total_inv > MaterialWarningSetting.red_threshold) & else_=0
(total_inv <= MaterialWarningSetting.yellow_threshold), )
total_inv - MaterialWarningSetting.red_threshold
),
else_=999999 # 正常物料放在最后
).label('yellow_gap')
# 添加排序字段到查询 # 黄色组内部:距离红线越近越靠前 (total_inv - red_threshold) ASC
query = query.add_columns(warning_status, red_gap, yellow_gap) yellow_distance = case(
(and_(MaterialWarningSetting.is_enabled == True, total_inv > MaterialWarningSetting.red_threshold, total_inv <= MaterialWarningSetting.yellow_threshold),
total_inv - MaterialWarningSetting.red_threshold),
else_=999999999 # 给一个极大值,让非黄色组沉底,不影响升序
)
# 强制排序规则:预警状态降序 -> 红色缺口降序 -> 黄色余量升序 -> 规格型号升 # 清除默认排序,应用全新的四级混合排
query = query.order_by( query = query.order_by(
warning_status.desc(), desc(warning_level),
red_gap.desc(), desc(red_shortage),
yellow_gap.asc(), asc(yellow_distance),
MaterialBase.spec_model.asc() desc(MaterialBase.id) # 常规组兜底排序
) )
elif order_by_column: elif order_by_column:
# 字段映射 # 字段映射