feat: BOM型号可编辑 + 生产订单BOM去括号 + 物料明细各工厂实时库存
- BOM编辑页「型号」输入框取消 readonly,可修改;bom_edit 增加非空与唯一校验(重复提示「BOM 型号已存在」、空值提示「BOM 型号必填」),改名不影响关联生产订单与流水 - 生产订单列表/详情/表单中 BOM 显示由 CODE (NAME) 改为 CODE · NAME,去掉括号 - 物料明细页新增「各工厂实时库存」表(工厂编号/名称/实时库存),显示每个工厂的实时聚合库存(入−出),不受顶栏工厂过滤影响
This commit is contained in:
@@ -831,11 +831,21 @@ def material_detail(mid):
|
||||
stmt_out.order_by(Outbound.occur_date.desc(), Outbound.id.desc())
|
||||
).all()
|
||||
fmap = {f.id: f.name for f in db.session.scalars(db.select(Factory)).all()}
|
||||
# 各工厂实时库存(按工厂拆分, 实时聚合 inbound-outbound)
|
||||
inb_by_f = {r[0]: float(r[1]) for r in db.session.execute(
|
||||
db.text("SELECT factory_id, COALESCE(SUM(qty),0) FROM inbound WHERE material_id=:mid GROUP BY factory_id"),
|
||||
{"mid": mid}).fetchall()}
|
||||
out_by_f = {r[0]: float(r[1]) for r in db.session.execute(
|
||||
db.text("SELECT factory_id, COALESCE(SUM(qty),0) FROM outbound WHERE material_id=:mid GROUP BY factory_id"),
|
||||
{"mid": mid}).fetchall()}
|
||||
per_factory = [{"f": f, "stock": inb_by_f.get(f.id, 0) - out_by_f.get(f.id, 0)}
|
||||
for f in db.session.scalars(db.select(Factory).order_by(Factory.code)).all()]
|
||||
return render_template("material_detail.html", m=m,
|
||||
stock=sm.get(m.id, 0),
|
||||
inb_total=inb_total.get(m.id, 0),
|
||||
out_total=out_total.get(m.id, 0),
|
||||
inbounds=inbounds, outbounds=outbounds, fmap=fmap)
|
||||
inbounds=inbounds, outbounds=outbounds, fmap=fmap,
|
||||
per_factory=per_factory)
|
||||
|
||||
|
||||
# ---------------- 入库 / 出库 ----------------
|
||||
@@ -1366,8 +1376,21 @@ def bom_edit(bid):
|
||||
return redirect(url_for("boms"))
|
||||
mats = db.session.scalars(db.select(Material).order_by(Material.part_number)).all()
|
||||
if request.method == "POST":
|
||||
# BOM 型号(简码)可编辑: 校验非空 + 不与其它 BOM 重复
|
||||
new_code = request.form.get("code", "").strip()
|
||||
b.name = request.form.get("name", "")
|
||||
b.note = request.form.get("note", "")
|
||||
raw = db.session.scalars(db.select(BomItem).where(BomItem.bom_id == b.id)).all()
|
||||
items = [{"pn": db.session.get(Material, it.material_id).part_number,
|
||||
"qty": it.qty_per_unit} for it in raw]
|
||||
if not new_code:
|
||||
flash("BOM 型号必填", "error")
|
||||
return render_template("bom_form.html", b=b, mats=mats, items=items, form_code=new_code)
|
||||
dup = db.session.scalar(db.select(Bom).where(Bom.code == new_code, Bom.id != b.id))
|
||||
if dup:
|
||||
flash("BOM 型号已存在", "error")
|
||||
return render_template("bom_form.html", b=b, mats=mats, items=items, form_code=new_code)
|
||||
b.code = new_code
|
||||
db.session.execute(db.delete(BomItem).where(BomItem.bom_id == b.id))
|
||||
pns = request.form.getlist("pn")
|
||||
qts = request.form.getlist("qty")
|
||||
|
||||
Reference in New Issue
Block a user