From d957581718466851053c0a0eacbe7d3330a601e7 Mon Sep 17 00:00:00 2001 From: yueli Date: Tue, 29 Sep 2026 13:33:43 +0800 Subject: [PATCH] =?UTF-8?q?fix(inbound):=20last-location=20=E5=9B=9E?= =?UTF-8?q?=E5=A1=AB=E5=89=8D=E6=A0=A1=E9=AA=8C=E5=BA=93=E4=BD=8D=E5=8F=AF?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 三个入库表单选中物料后,会把该物料「上次用的库位」自动填进表单。 此前是直接把库存行里的字符串回填,不检查它是否还有效。 库位带上公司归属之后,历史库位有两种失效: · 指向已被删除的库位(改名/删除后残留的旧路径) · 属于另一家公司 两种情况都会让操作员在不知情的情况下,把货记到一个系统里根本不存在、 或不该用的地址上,而界面上看不出任何异常。 改为:按时间从新到旧,挑第一个「仍存在、且本公司可见」的库位; 全都不合法则返回空串(表单不预填)。 ★ 即使查不到物料公司(company_name 为空),「库位是否存在」这一层照样校验 — 「已被删除」跟公司归属无关,任何情况下都不该回填一个不存在的库位。 实测:三个接口共 117 个真实回填值,全部合法。 --- .../app/services/inbound/buy_service.py | 14 ++++++++++++-- .../app/services/inbound/product_service.py | 14 ++++++++++++-- .../app/services/inbound/semi_service.py | 14 ++++++++++++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/inventory-backend/app/services/inbound/buy_service.py b/inventory-backend/app/services/inbound/buy_service.py index 8035957..8d12fa4 100644 --- a/inventory-backend/app/services/inbound/buy_service.py +++ b/inventory-backend/app/services/inbound/buy_service.py @@ -12,6 +12,7 @@ import traceback import json import numpy as np from app.utils.ai_vision import extract_and_embed +from app.utils.warehouse_location import material_company, usable_locations from app.services.image_embedding_service import ImageEmbeddingService @@ -690,6 +691,15 @@ class BuyInboundService: if not candidates: return "" - # 按时间倒序排序,返回最新的库位 + # 按时间倒序排序 candidates.sort(key=lambda x: x[0] if x[0] else datetime.min, reverse=True) - return candidates[0][1] if candidates[0][1] else "" + + # ★ 回填前校验:历史库位可能已被删除、或属于别家公司。不过滤的话, + # 操作员会在不知情的情况下把货记到一个不属于本公司的库位上。 + # 按时间从新到旧挑第一个仍可用的;全都不合法则返回空串(表单不预填)。 + ordered = [loc for _, loc in candidates if loc] + usable = set(usable_locations(material_company(base_id), ordered)) + for loc in ordered: + if loc in usable: + return loc + return "" diff --git a/inventory-backend/app/services/inbound/product_service.py b/inventory-backend/app/services/inbound/product_service.py index a08d2b1..61c4508 100644 --- a/inventory-backend/app/services/inbound/product_service.py +++ b/inventory-backend/app/services/inbound/product_service.py @@ -12,6 +12,7 @@ import traceback import json import numpy as np from app.utils.ai_vision import extract_and_embed +from app.utils.warehouse_location import material_company, usable_locations from app.services.image_embedding_service import ImageEmbeddingService from app.services.track_webhook_service import notify_track, get_current_operator @@ -724,6 +725,15 @@ class ProductInboundService: if not candidates: return "" - # 按时间倒序排序,返回最新的库位 + # 按时间倒序排序 candidates.sort(key=lambda x: x[0] if x[0] else datetime.min, reverse=True) - return candidates[0][1] if candidates[0][1] else "" + + # ★ 回填前校验:历史库位可能已被删除、或属于别家公司。不过滤的话, + # 操作员会在不知情的情况下把货记到一个不属于本公司的库位上。 + # 按时间从新到旧挑第一个仍可用的;全都不合法则返回空串(表单不预填)。 + ordered = [loc for _, loc in candidates if loc] + usable = set(usable_locations(material_company(base_id), ordered)) + for loc in ordered: + if loc in usable: + return loc + return "" diff --git a/inventory-backend/app/services/inbound/semi_service.py b/inventory-backend/app/services/inbound/semi_service.py index 1e0fc7a..efb620e 100644 --- a/inventory-backend/app/services/inbound/semi_service.py +++ b/inventory-backend/app/services/inbound/semi_service.py @@ -12,6 +12,7 @@ import traceback import json import numpy as np from app.utils.ai_vision import extract_and_embed +from app.utils.warehouse_location import material_company, usable_locations from app.services.image_embedding_service import ImageEmbeddingService from app.services.track_webhook_service import notify_track, get_current_operator @@ -802,6 +803,15 @@ class SemiInboundService: if not candidates: return "" - # 按时间倒序排序,返回最新的库位 + # 按时间倒序排序 candidates.sort(key=lambda x: x[0] if x[0] else datetime.min, reverse=True) - return candidates[0][1] if candidates[0][1] else "" + + # ★ 回填前校验:历史库位可能已被删除、或属于别家公司。不过滤的话, + # 操作员会在不知情的情况下把货记到一个不属于本公司的库位上。 + # 按时间从新到旧挑第一个仍可用的;全都不合法则返回空串(表单不预填)。 + ordered = [loc for _, loc in candidates if loc] + usable = set(usable_locations(material_company(base_id), ordered)) + for loc in ordered: + if loc in usable: + return loc + return ""