V3.50
This commit is contained in:
@ -388,25 +388,31 @@ class BomService:
|
||||
# 1. 提取所有子件的 ID 列表
|
||||
child_ids = [child['child_id'] for child in detail['children']]
|
||||
|
||||
# 2. 用一条 IN 语句批量查出所有相关子件的库存和库位
|
||||
stock_stats = db.session.query(
|
||||
StockBuy.base_id,
|
||||
func.coalesce(func.sum(StockBuy.available_quantity), 0).label('total_qty'),
|
||||
func.string_agg(distinct(StockBuy.warehouse_location), ', ').label('locations')
|
||||
).filter(
|
||||
StockBuy.base_id.in_(child_ids),
|
||||
StockBuy.available_quantity > 0
|
||||
).group_by(
|
||||
StockBuy.base_id
|
||||
).all()
|
||||
# 2. 分别查三张库存表,Python 侧合并聚合(避免 UNION ALL 子查询列名问题)
|
||||
from collections import defaultdict
|
||||
stock_agg = defaultdict(lambda: {'qty': 0.0, 'locs': set()})
|
||||
|
||||
# 3. 将查询结果转换为字典 (Map),方便后续 O(1) 极速匹配
|
||||
for model in (StockBuy, StockSemi, StockProduct):
|
||||
rows = db.session.query(
|
||||
model.base_id,
|
||||
model.available_quantity,
|
||||
model.warehouse_location
|
||||
).filter(
|
||||
model.base_id.in_(child_ids),
|
||||
model.available_quantity > 0
|
||||
).all()
|
||||
for base_id, qty, loc in rows:
|
||||
stock_agg[base_id]['qty'] += float(qty or 0)
|
||||
if loc:
|
||||
stock_agg[base_id]['locs'].add(loc)
|
||||
|
||||
# 3. 将聚合结果转换为字典 (Map),方便后续 O(1) 极速匹配
|
||||
stock_map = {
|
||||
stat.base_id: {
|
||||
'qty': stat.total_qty,
|
||||
'loc': stat.locations if stat.locations else ''
|
||||
base_id: {
|
||||
'qty': agg['qty'],
|
||||
'loc': ', '.join(sorted(agg['locs'])) if agg['locs'] else ''
|
||||
}
|
||||
for stat in stock_stats
|
||||
for base_id, agg in stock_agg.items()
|
||||
}
|
||||
|
||||
# 4. 遍历组装数据(纯内存操作,极快)
|
||||
@ -480,17 +486,23 @@ class BomService:
|
||||
|
||||
parent_name = detail.get('parent_name', '')
|
||||
|
||||
# 2. 提取所有子件 ID,查询采购库存(stock_buy)
|
||||
# 2. 提取所有子件 ID,分别查三张库存表,Python 侧合并聚合
|
||||
child_ids = [child['child_id'] for child in detail['children']]
|
||||
|
||||
buy_stats = db.session.query(
|
||||
StockBuy.base_id,
|
||||
func.coalesce(func.sum(StockBuy.available_quantity), 0).label('total_qty')
|
||||
).filter(
|
||||
StockBuy.base_id.in_(child_ids)
|
||||
).group_by(StockBuy.base_id).all()
|
||||
from collections import defaultdict
|
||||
stock_agg = defaultdict(float)
|
||||
|
||||
buy_map = {stat.base_id: float(stat.total_qty) for stat in buy_stats}
|
||||
for model in (StockBuy, StockSemi, StockProduct):
|
||||
rows = db.session.query(
|
||||
model.base_id,
|
||||
model.available_quantity
|
||||
).filter(
|
||||
model.base_id.in_(child_ids)
|
||||
).all()
|
||||
for base_id, qty in rows:
|
||||
stock_agg[base_id] += float(qty or 0)
|
||||
|
||||
stock_map = dict(stock_agg)
|
||||
|
||||
# 3. 提取所有子件的基础物料信息(名称/规格/类型)
|
||||
materials = db.session.query(
|
||||
@ -511,7 +523,7 @@ class BomService:
|
||||
dosage = float(child.get('dosage') or 0)
|
||||
need_qty = dosage * order_qty
|
||||
|
||||
available_stock = buy_map.get(child_id, 0)
|
||||
available_stock = stock_map.get(child_id, 0)
|
||||
suggested_qty = max(0.0, min(need_qty, available_stock))
|
||||
gap = available_stock - need_qty
|
||||
|
||||
|
||||
Reference in New Issue
Block a user