fix: correct BOM cost calculation by using raw SQL and manual_cost

Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
This commit is contained in:
dxc
2026-03-02 11:47:44 +08:00
parent 7b0082c6e0
commit d3510b0261

View File

@ -399,34 +399,46 @@ class ProductInboundService:
def calculate_bom_cost(bom_no, bom_version):
"""
根据 BOM 编号和版本计算原材料总成本
遍历 BOM 子件,取每个子件在采购、半成品、成品三个表中的最高单价,乘以用量后累加
遍历 BOM 子件,使用原生 SQL 查物理表 bom_table取每个子件在采购、半成品、成品三个表中的最高单价,乘以用量后累加
"""
from app.models.bom import BomLine
from app.models.inbound.buy import StockBuy
from app.models.inbound.semi import StockSemi
from app.models.inbound.product import StockProduct
from sqlalchemy import func
from sqlalchemy import func, text
try:
bom_lines = BomLine.query.filter(
BomLine.bom_no == bom_no,
BomLine.bom_version == bom_version
).all()
# 使用原生 SQL 精准查询 bom_table避免模型映射错误
sql = text("""
SELECT child_id, dosage
FROM bom_table
WHERE bom_no = :bom_no AND version = :version AND is_enabled = true
""")
bom_lines = db.session.execute(sql, {'bom_no': bom_no, 'version': bom_version}).fetchall()
total_cost = 0.0
for line in bom_lines:
component_base_id = line.component_id
usage_qty = float(line.usage_quantity or 1.0)
component_base_id = line[0] # child_id
usage_qty = float(line[1] or 1.0) # dosage
# 1. 查采购表最高价 (不含税)
buy_price = db.session.query(func.max(StockBuy.pre_tax_unit_price)).filter(
StockBuy.base_id == component_base_id).scalar() or 0.0
semi_price = db.session.query(func.max(StockSemi.unit_total_cost)).filter(
StockSemi.base_id == component_base_id).scalar() or 0.0
product_price = db.session.query(func.max(StockProduct.unit_total_cost)).filter(
StockProduct.base_id == component_base_id).scalar() or 0.0
max_price = max(buy_price, semi_price, product_price)
StockBuy.base_id == component_base_id
).scalar() or 0.0
# 2. 查半成品表最高价 (单件成本映射存在 manual_cost 里了)
semi_price = db.session.query(func.max(StockSemi.manual_cost)).filter(
StockSemi.base_id == component_base_id
).scalar() or 0.0
# 3. 查成品表最高价 (同样存储在 manual_cost 字段里)
product_price = db.session.query(func.max(StockProduct.manual_cost)).filter(
StockProduct.base_id == component_base_id
).scalar() or 0.0
# 4. 取三个表中的最大值,乘以用量 (dosage)
max_price = max(float(buy_price), float(semi_price), float(product_price))
total_cost += max_price * usage_qty
return round(total_cost, 2)
except Exception as e:
traceback.print_exc()
raise e
raise e