fix(borrow): 修复借还记录排序被静默丢弃,无限期改按借出时间从近到远

现象
----
借还记录列表的排序看起来毫无规律:无限期单排在有限期前面,有限期内
10-01 排在 11-01 之后。业务方反馈「不是逾期的、剩余天数最近的排前面吗?」

根因
----
三级复合排序(trans_service get_records 步骤 2)算得完全正确,但**结果被
后面一步覆盖**:

    # 步骤 2:算出分页用的 page_borrow_nos(顺序正确)
    # 步骤 3:再按集合把明细拉回来 ——
    detail_records = TransBorrow.query.filter(borrow_no.in_(page_borrow_nos))
                          .order_by(TransBorrow.borrow_no.asc(), ...)

单号形如 BOR-YYYYMMDD-NNNN,**它的字母序恰好等于借出日期序**。于是这 10 条
明细被重排成「按借出日期升序」,那份精心设计的排序被整套丢弃。

实测(修复前,未归还页签第 1 页):
    1 BOR-20260413-0001  无限期  04-13   ← 无限期在最前
    4 BOR-20260611-0001  无限期  06-11
    5 BOR-20260903-0010  逾期    09-10   ← 逾期单反而最后
    8 BOR-20260904-0005  10-01            ← 10-01 排在 11-01 之后

★ 该功能自上线起从未生效:
    1450e6c (06-16) 引入按 borrow_no 重排的明细拉取
    73510d3 (09-04) 才加入三级复合排序 —— 加在了被覆盖的路径上,
                    提交信息「借还记录默认排序重构」名存实亡。

修复
----
按 page_borrow_nos 的顺序还原输出(明细内部仍按 id 升序,即扫码顺序)。
同时按业务方要求调整第二梯队方向:

  ① 有限期单在前(有任何明细含预计归还时间)
  ② 有限期内按单内最早预计归还时间**升序** —— 逾期优先,其后剩余天数由近到远
  ③ 无限期内按单内最早借出时间**降序**(从近到远)
     ★ 原为升序「借出越久越靠前,暴露呆滞借用」,业务方明确要求反转

修复后实测(未归还页签):
    有限期 09-10(逾期7天) → 09-11(逾期6天) → 09-15(逾期2天) → 10-01 → 11-01 → 11-27
    无限期 09-17 → 09-14 → 09-11 → 09-10 → … → 04-13(跨页连续)

验证:borrowed / returned 两个页签各 3 页顺序全部核对通过;关键词、物料名、
高级筛选、日期范围、空结果六条过滤路径冒烟通过;同单号明细未被跨单号打散。
This commit is contained in:
yueli
2026-09-17 09:53:26 +08:00
parent b1f39acb97
commit 15d0c6b97a

View File

@ -1216,7 +1216,10 @@ class TransService:
borrow_no_q = borrow_no_q.order_by(
case((order_subq.c.has_finite == 0, 1), else_=0).asc(),
nullslast(asc(order_subq.c.sort_key)),
asc(order_subq.c.min_borrow_time)
# ★ 无限期梯队内按借出时间**从近到远**desc
# 原实现是 asc「借出越久越靠前」设计意图是暴露呆滞借用
# 业务方明确要求改为从近到远,故反转。
desc(order_subq.c.min_borrow_time)
)
# 分页(基准 = borrow_no 单号数)
@ -1311,6 +1314,23 @@ class TransService:
item_dict['material_name'] = material_name
items_with_names.append(item_dict)
# ====================================================================
# ★ 恢复业务排序(此前被静默丢弃)
#
# detail_records 是按 `borrow_no ASC` 重新拉取的,而单号形如
# BOR-YYYYMMDD-NNNN —— 它的**字母序恰好等于借出日期序**。
# 于是上面步骤 2 辛苦算出的「逾期优先」分页顺序page_borrow_nos
# 被这次重排**整套覆盖**:无限期单排到了最前,有限期里 10-01 排在
# 11-01 之后,看起来完全随机。那份 ORDER BY 一直是死代码。
#
# 这里按 page_borrow_nos 的顺序还原输出。明细内部仍按 id 升序
# 同一次发货写入的明细id 序即扫码顺序,便于阅读)。
# ====================================================================
_order_idx = {bn: i for i, bn in enumerate(page_borrow_nos)}
items_with_names.sort(
key=lambda d: (_order_idx.get(d.get('borrow_no'), len(_order_idx)), d.get('id') or 0)
)
return {
'items': items_with_names,
'total': total_orders,